Bash读/写文件描述符 - 寻找文件的开头

tel*_*ium 12 unix linux bash file-io read-write

我尝试在bash中使用读/写文件描述符,以便我可以删除文件描述符后面引用的文件,如下所示:

F=$(mktemp)
exec 3<> "$F"
rm -f "$F"

echo "Hello world" >&3
cat <&3
Run Code Online (Sandbox Code Playgroud)

但该cat命令没有输出.如果我使用单独的文件描述符进行读写,我可以实现我想要的:

F=$(mktemp)
exec 3> "$F"
exec 4< "$F"
rm -f "$F"

echo "Hello world" >&3
cat <&4
Run Code Online (Sandbox Code Playgroud)

打印Hello world.

我怀疑当你从写入切换到读取时,bash不会自动寻找文件描述符的开头,以下bash和python代码的组合证实了这一点:

fdrw.sh

exec 3<> tmp
rm tmp

echo "Hello world" >&3
exec python fdrw.py
Run Code Online (Sandbox Code Playgroud)

fdrw.py

import os  

f = os.fdopen(3)
print f.tell()
print f.read()
Run Code Online (Sandbox Code Playgroud)

这使:

$ bash fdrw.sh
12

$ # This is the prompt reappearing
Run Code Online (Sandbox Code Playgroud)

有没有办法实现我想要的只是使用bash?

tel*_*ium 8

如果您碰巧想要在bash文件描述符上进行搜索,则可以使用子进程,因为它继承了父进程的文件描述符.这是一个示例C程序来执行此操作.

seekfd.c

#define _FILE_OFFSET_BITS 64
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    /* Arguments: fd [offset [whence]]
     * where
     * fd: file descriptor to seek
     * offset: number of bytes from position specified in whence
     * whence: one of
     *  SEEK_SET (==0): from start of file
     *  SEEK_CUR (==1): from current position
     *  SEEK_END (==2): from end of file
     */
    int fd;
    long long scan_offset = 0;
    off_t offset = 0;
    int whence = SEEK_SET;
    int errsv; int rv;
    if (argc == 1) {
        fprintf(stderr, "usage: seekfd fd [offset [whence]]\n");
        exit(1);
    }
    if (argc >= 2) {
        if (sscanf(argv[1], "%d", &fd) == EOF) {
            errsv = errno;
            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));
            exit(1);
        }
    }
    if (argc >= 3) {
        rv = sscanf(argv[2], "%lld", &scan_offset);
        if (rv == EOF) {
            errsv = errno;
            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));
            exit(1);
        }
        offset = (off_t) scan_offset;
    }
    if (argc >= 4) {
        if (sscanf(argv[3], "%d", &whence) == EOF) {
            errsv = errno;
            fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));
            exit(1);
        }
    }

    if (lseek(fd, offset, whence) == (off_t) -1) {
        errsv = errno;
        fprintf(stderr, "%s: %s\n", argv[0], strerror(errsv));
        exit(2);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*aro 8

我找到了一种在bash中实现它的方法,但它依赖于一个不起眼的功能,exec < /dev/stdin它实际上可以根据http://linux-ip.net/misc/madlug/shell-tips/tip-1重绕stdin的文件描述符..txt:

F=$(mktemp)
exec 3<> "$F"
rm -f "$F"

echo "Hello world" >&3
{ exec < /dev/stdin; cat; } <&3
Run Code Online (Sandbox Code Playgroud)

写描述符不受此影响,因此您仍然可以在cat之前将输出附加到描述符3.

可悲的是,我只在Linux下工作,而不是MacOS(BSD),即使使用最新的bash版本.所以它似乎不太便携.


Ign*_*ams 6

不,bash 的重定向没有任何“寻求”的概念。它在一个长流中从头到尾读/写(大部分)。

  • 那么,基本上,bash 中读/写描述符的唯一原因是将它们传递给一个 exec'ed 进程? (2认同)

小智 5

尝试更改命令序列:

F=$(mktemp tmp.XXXXXX)
exec 3<> "$F"
echo "Hello world" > "$F"
rm -f "$F"

#echo "Hello world" >&3
cat <&3
Run Code Online (Sandbox Code Playgroud)

  • @Dennis这个解决方案确实有效.猫没有从明显删除的文件中读取.它正在从仍然开放的描述符中读取.您仍然可以使用该描述符访问文件的内容,即使已删除了它的最后一个(硬)链接. (6认同)

PSk*_*cik 5

像这样在bash中打开文件描述符时,它可以作为中的文件访问/dev/fd/。可以做到cat这一点,它将从头开始读取,或附加(echo "something" >> /dev/fd/3),并将其添加到末尾。至少在我的系统上,它的行为是这样的。(另一方面,即使我不对描述符进行任何写入,我似乎也无法使“ cat <&3”正常工作)。