假设我有一个名为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
我不明白为什么使用*
不能正常工作。
有其他选择吗?
答案 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 "$@"' _