繁体   English   中英

文件命令中的进程替换有问题

[英]Trouble with the process substitution in the file command

更容易显示为试图用文字描述。

find . -name jo\* -print > list
cat list
#./jo1
#./jo2
#./jo3

# the "file" by reading the list of files from the file "list"
file -f list
#./jo1: ASCII text
#./jo2: ASCII text
#./jo3: ASCII text

#now with process substitution
file -f <(find . -name jo\* -print)

没有输出..;(

#repeat with -x
set -x
file -f <(find . -name jo\* -print)
set +x

#shows
+ file -f /dev/fd/63
++ find . -name 'jo*' -print
+ set +x

所以,它应该工作。 但不是。 为什么?

编辑

请注意 - 进程替换应该适用于您应该输入文件名的所有位置,让我们说:

diff <(some command) <(another command)

以上用作bash

diff /dev/fd/... /dev/fd/...

例如在grep - 你可以使用:

grep -f <(command_for_produce_the_patterns) files..

再次, bash内部使用它作为

grep -f /dev/fd/63 files....

所以,同样应该file工作

file -f <(command)

你做得对。 这是你的file实现中的一个错误,我可以在我的文件中重现(Debian jessie上的文件5.22)。 它期望-f的参数是可搜索文件,并且在文件不可搜索时不检测错误。 这就是为什么它适用于常规文件,而不是管道(这是进程替换用于在两个进程之间传递数据的原因)。

您可以通过strace观察正在发生的事情:

$ strace file -f <(echo foo)
…
open("/proc/self/fd/13", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
…
read(3, "foo\n", 4096)                 = 5
…
read(3, "", 4096)                       = 0
lseek(3, 0, SEEK_SET)                   = -1 ESPIPE (Illegal seek)
read(3, "", 4096)                       = 0
close(3)                                = 0

文件程序打开文件描述符3上的文件名列表并读取它。 它试图寻找文件的开头。 这会失败,但程序会再次从文件中读取,因为文件位置已经结束,所以不会产生任何数据。 因此,文件以文件名的空列表结束。

在源代码中, -f选项触发unwrap函数:

private int
unwrap(struct magic_set *ms, const char *fn)
{
    // …
    if (strcmp("-", fn) == 0) {
            f = stdin;
            wid = 1;
    } else {
        if ((f = fopen(fn, "r")) == NULL) {
                (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n",
                    progname, fn, strerror(errno));
                return 1;
        }
        while ((len = getline(&line, &llen, f)) > 0) {
            // … code to determine column widths
        }
        rewind(f);
    }
    // Code to read the file names from f follows
}

如果文件名不是- (指示从标准输入读取),则代码读取文件两次,一次确定文件名的最大宽度,一次处理文件。 rewind的调用缺少错误处理。 使用-作为文件名,代码不会尝试对齐列。

不使用<(cmd)语法,而是使用$(cmd)。 这应该克服这个bug

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM