Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux Bash读/写文件描述符--查找文件的开头_Linux_Bash_Unix_File Io_Read Write - Fatal编程技术网

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

Linux Bash读/写文件描述符--查找文件的开头,linux,bash,unix,file-io,read-write,Linux,Bash,Unix,File Io,Read Write,我尝试在bash中使用读/写文件描述符,以便删除文件描述符随后引用的文件,如下所示: F=$(mktemp) exec 3<> "$F" rm -f "$F" echo "Hello world" >&3 cat <&3 它会打印出Hello world 我怀疑,当您从写入切换到读取文件描述符时,bash不会自动寻找文件描述符的开头,下面的bash和python代码组合证实了这一点: fdrw.sh exec 3<> tmp rm tmp

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

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

echo "Hello world" >&3
cat <&3
它会打印出Hello world

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

fdrw.sh

exec 3<> tmp
rm tmp

echo "Hello world" >&3
exec python fdrw.py
其中:

$ bash fdrw.sh
12

$ # This is the prompt reappearing

有没有一种方法可以通过使用bash实现我想要的功能?

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

尝试更改命令顺序:

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

#echo "Hello world" >&3
cat <&3
F=$(mktemp tmp.XXXXXX)
执行官3“$F”
echo“Hello world”>“$F”
rm-f“$f”
#echo“Hello world”>&3

cat如果您碰巧想要在bash文件描述符上查找,可以使用子进程,因为它继承父进程的文件描述符。下面是一个示例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;
}
定义文件偏移量64位
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
/*参数:fd[offset[whence]]
*在哪里
*fd:要查找的文件描述符
*偏移量:从何处指定的位置开始的字节数
*从哪里来的:其中一个
*SEEK_SET(=0):从文件开始
*SEEK_CUR(=1):从当前位置开始
*SEEK_END(=2):从文件末尾开始
*/
int-fd;
长扫描偏移量=0;
off_t offset=0;
int whence=搜索集;
int errsv;int rv;
如果(argc==1){
fprintf(stderr,“用法:参见kfd fd[偏移量[从何处]]\n”);
出口(1);
}
如果(argc>=2){
如果(sscanf(argv[1]、%d”、&fd)=EOF){
errsv=errno;
fprintf(stderr,“%s:%s\n”,argv[0],strerror(errsv));
出口(1);
}
}
如果(argc>=3){
rv=sscanf(argv[2],%lld“,&scan\u偏移量);
如果(rv==EOF){
errsv=errno;
fprintf(stderr,“%s:%s\n”,argv[0],strerror(errsv));
出口(1);
}
偏移量=(关闭)扫描偏移量;
}
如果(argc>=4){
如果(sscanf(argv[3],%d”,&whence)=EOF){
errsv=errno;
fprintf(stderr,“%s:%s\n”,argv[0],strerror(errsv));
出口(1);
}
}
if(lseek(fd,offset,whence)=(off_t)-1){
errsv=errno;
fprintf(stderr,“%s:%s\n”,argv[0],strerror(errsv));
出口(2);
}
返回0;
}

我在bash中找到了一种方法,但它依赖于
exec
的一个模糊功能,该功能实际上可以根据以下内容回放stdin的文件描述符:

F=$(mktemp)
执行官3“$F”
rm-f“$f”
echo“Hello world”>&3

{exec/dev/fd/
中的一个文件进行访问。 在此基础上,您可以执行
cat
,它将从头开始读取,或者附加(
echo“something”>/dev/fd/3
),并将其添加到末尾。 至少在我的系统中,它是这样运行的。(另一方面,我似乎无法获得“cat
!/bin/bash”
F=$(mktemp tmp.XXXXXX)
执行官3$F
rm$F
echo“Hello world”>&3
cat/dev/fd/3

在另一个答案中,
cat
会在读取文件描述符之前为您倒带它,因为它认为它只是一个普通文件。

要“倒带”文件描述符,您只需使用
/proc/self/fd/3

测试脚本:

#!/bin/bash

# Fill data
FILE=test
date +%FT%T >$FILE

# Open the file descriptor and delete the file
exec 5<>$FILE
rm -rf $FILE

# Check state of the file
# should return an error as the file has been deleted
file $FILE

# Check that you still can do multiple reads or additions
for i in {0..5}; do
    echo ----- $i -----

    echo . >>/proc/self/fd/5
    cat /proc/self/fd/5

    echo
    sleep 1
done
!/bin/bash
#填充数据
文件=测试
日期+%FT%T>$文件
#打开文件描述符并删除该文件
exec 5$文件
rm-rf$文件
#检查文件的状态
#应返回一个错误,因为文件已被删除
文件$file
#检查您是否仍然可以进行多次读取或添加
因为{0..5}中的i;do
回声------1美元-----
echo.>>/proc/self/fd/5
cat/proc/self/fd/5
回声
睡眠1
完成

尝试在脚本运行时杀死-9脚本,您会发现与trap方法相反,文件实际上被删除了。

基本上,bash中读/写描述符的唯一原因是将它们传递给执行进程?以便提供更多通道,而不仅仅是stdin、stdout和sterr,是的使用网络连接进行sed…
exec{w}/dev/tcp/www.google.com/80
,您可以使用它写入文件的中间部分。您可以打开文件读/写,读取N个字符,然后写入。搜索“读和写”"例如,在Unix中,在读取/写入文件之前,为什么要删除该文件?在Unix中,删除文件时,直到关闭所有打开的文件描述符后,该文件才被实际删除。因此,在打开后立即删除临时文件是一种常见做法,因为它保证没有其他进程会恶意更改该文件和文件进程关闭文件或退出后,文件不会关闭。为什么不喜欢自己的方法,使用单独的读写描述符?这似乎是最简单的方法。@Dennis此解决方案实际上是有效的。cat不会读取明显已删除的文件。它是从仍然打开的描述符读取。您仍然可以访问具有该描述符的文件内容,即使最后一个(硬)指向它的链接已被删除。此解决方案的问题是,
echo
可能需要很长时间,这意味着临时文件会在文件系统中保留很长时间。如果这是可以接受的,那么您可以简单地使用文件名,而不是fd 3来重定向。我确信会有一个oneliner,它可以做同样的事情,并且更具移植性ble
#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;
}
F=$(mktemp)
exec 3<> "$F"
rm -f "$F"

echo "Hello world" >&3
{ exec < /dev/stdin; cat; } <&3
#!/bin/bash
F=$(mktemp tmp.XXXXXX)
exec 3<> $F
rm $F

echo "Hello world" >&3
cat /dev/fd/3
#!/bin/bash

# Fill data
FILE=test
date +%FT%T >$FILE

# Open the file descriptor and delete the file
exec 5<>$FILE
rm -rf $FILE

# Check state of the file
# should return an error as the file has been deleted
file $FILE

# Check that you still can do multiple reads or additions
for i in {0..5}; do
    echo ----- $i -----

    echo . >>/proc/self/fd/5
    cat /proc/self/fd/5

    echo
    sleep 1
done