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

caj*_*ine 4 bash shell pipe

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

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)
Run Code Online (Sandbox Code Playgroud)

没有输出..;(

#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
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

diff <(some command) <(another command)
Run Code Online (Sandbox Code Playgroud)

以上用作bash

diff /dev/fd/... /dev/fd/...
Run Code Online (Sandbox Code Playgroud)

例如,grep你可以使用:

grep -f <(command_for_produce_the_patterns) files..
Run Code Online (Sandbox Code Playgroud)

再次,bash内部使用它作为

grep -f /dev/fd/63 files....
Run Code Online (Sandbox Code Playgroud)

所以,同样应该file

file -f <(command)
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 5

你做得对.这是你实现的一个错误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
Run Code Online (Sandbox Code Playgroud)

文件程序打开文件描述符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
}
Run Code Online (Sandbox Code Playgroud)

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