xargs -I {} ls {}* :无法访问没有这样的文件或目录

xargs -I {} ls {}* : cannot access no such file or directory

假设我有一个名为 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

我不明白为什么它不能使用 *。 有替代方案吗?

why it doesn't work using the *

文件名扩展(即用文件参数列表替换 *)由 shell 完成,因此要将 * 扩展到您拥有的文件名列表调用 shell。因为 xargs 在传递参数时不调用 shell,所以没有任何东西可以将 * 扩展到文件列表。因为您没有字面上名为 * 的文件,所以 ls 退出并出错。

Is there an alternative ?

你可以:

# 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 ""/*' _

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

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

或者不使用 shell 文件名扩展,而是使用具有类似但不同行为的查找:

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

您也可以将 ls 调用从文件名扩展中分离出来,分两次进行 - 首先 运行 文件名扩展,然后结果列表传递给 ls:

printf "%s[=13=]" * | xargs -0 -n1 sh -c 'printf "%s[=13=]" ""/*' _ | xargs -0 ls

可能你可以正确引用参数列表并用 /* 后缀,然后重新 evalulate 列表以在所有参数上触发 * 上的文件名扩展,这将只调用一个 ls 和一个 subshell 所以是最快的(虽然 eval 看起来很危险而且我担心它,但它似乎工作正常):

printf "%q/*[=14=]" * | xargs -0 sh -c 'eval ls "$@"' _