bash - xargs -I {} ls {}* : 无法访问没有这样的文件或目录
问题描述
假设我有一个名为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
我不明白为什么它不能使用*
. 有替代方案吗?
解决方案
为什么使用 * 不起作用
文件名扩展(即用*
文件的参数列表替换)由 shell 完成,因此要扩展*
为文件名列表,您必须调用 shell。因为xargs
在传递参数时不调用 shell,所以没有什么可以扩展*
为文件列表。因为您没有按*
字面命名的文件,所以会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"/*' _
或者使用具有相似但不同行为的 find 来代替 shell 文件名扩展:
find . -maxdepth 1 -mindepth 1 | xargs -d'\n' ...
find . -maxdepth 1 -mindepth 1 -print0 | xargs -0 ...
您还可以将ls
调用从文件名扩展中分离出来,并分两遍进行 - 首先对文件运行文件名扩展,然后将结果列表传递给 to ls
:
printf "%s\0" * | xargs -0 -n1 sh -c 'printf "%s\0" "$1"/*' _ | xargs -0 ls
潜在地,您可以正确引用参数列表并为它们添加后缀/*
,然后重新eval
调整列表以触发*
所有参数的文件名扩展,这将只调用一个ls
和一个子 shell,因此速度最快(而 eval 看起来很危险,我害怕它,它似乎工作正常):
printf "%q/*\0" * | xargs -0 sh -c 'eval ls "$@"' _
推荐阅读
- javascript - 使用 Jquery 的 AJAX 分页插件
- java - Swagger 生成的 java 对象不会正确映射 JSON 请求
- kubernetes - 如何以编程方式检测 kubernetes 集群是否已经有入口控制器?
- node.js - Cloud Function 停止响应随机外部 API 调用
- python - 当张量中有未知元素时,操纵张量形状的正确方法是什么?
- java - 已知格式时从字符串解析 JSON 的最快方法
- docker-compose - 如何在没有项目名称的情况下运行 docker-compose?
- excel - 循环查找 2 个字符串并复制到新工作表
- android - 有没有办法检查用户是否已经安装了应用程序
- mysql - 如何并排比较两个mysql表