xargs -I {} ls {} *:无法访问此类文件或目录

时间:2020-10-06 11:56:50

标签: bash xargs

假设我有一个名为test的工作目录。在此文件夹中,我有许多子目录:

$ ls */*
00/0a:
file1.txt

01/0b:
file2.txt

02/0c:
file3.txt

现在我想获得相同的结果,但是使用xargs:

$ ls | xargs -I {} ls {}/*
ls: cannot access 00/*: No such file or directory
ls: cannot access 01/*: No such file or directory
ls: cannot access 02/*: No such file or directory

我不明白为什么使用*不能正常工作。 有其他选择吗?

1 个答案:

答案 0 :(得分:2)

为什么不能使用*

文件名扩展(即用文件参数列表替换*)由外壳程序完成,因此要将*扩展到文件名列表,您必须调用外壳程序。由于xargs在传递参数时不会调用外壳程序,因此没有任何内容可以将*扩展到文件列表。由于您实际上没有名为*的文件,因此ls退出并出现错误。

还有其他选择吗?

您可以:

# DO NOT PARSE LS.
# Do not use xargs without -d when you do not want ' " \ to be handled specially.
# Do not pass arguments right into subshell, it's as unsafe as eval.
ls | xargs -I{} sh -c 'ls {}/*'
# Not really better as it parses ls.
ls | xargs -d'\n' -n1 sh -c 'ls "$1"/*' _

但是不要解析ls-而是根据文件名扩展生成列表:

# acceptable - newline separated list, properly passing arguments
printf "%s\n" * | xargs -d'\n' -n1 sh -c 'ls "$1"/*' _
# great - zero separated list, properly passing arguments
# ie. use this
printf "%s\0" * | xargs -0 -n1 sh -c 'ls "$1"/*' _

或者代替shell文件名扩展,使用具有相似但不同行为的find:

find . -maxdepth 1 -mindepth 1 | xargs -d'\n' ...
find . -maxdepth 1 -mindepth 1 -print0 | xargs -0 ...

您还可以从文件名扩展中拆分ls调用,并分两步进行-首先在文件上运行文件名扩展,然后将结果列表传递给ls

printf "%s\0" * | xargs -0 -n1 sh -c 'printf "%s\0" "$1"/*' _ | xargs -0 ls

可能您可以正确地引用参数列表并在其后缀/*,然后重新eval计算该列表以触发所有参数上*的文件名扩展,这将只需调用一个ls和一个子shell,以使其最快(因此评估似乎很危险,我担心它似乎可以正常工作):

printf "%q/*\0" * | xargs -0 sh -c 'eval ls "$@"' _