lon*_*nix 6 linux ls bash pipe cat
文件内容filelist:
/some/path/*.txt
/other/path/*.dat
/third/path/example.doc
Run Code Online (Sandbox Code Playgroud)
我想列出这些文件,所以我这样做:
cat filelist | xargs ls
Run Code Online (Sandbox Code Playgroud)
但我没有扩大这些球体,而是得到:
Run Code Online (Sandbox Code Playgroud)ls: cannot access '/some/path/*.txt': No such file or directory ls: cannot access '/other/path/*.dat': No such file or directory /third/path/example.doc
Sté*_*las 10
贝壳扩大球体。在这里,这是一种非常罕见的情况,其中隐式 split+glob 运算符在 zsh 以外的类似 Bourne 的 shell 中对未加引号的命令替换调用可能有用:
IFS='
' # split on newline only
set +o noglob # make sure globbing is not disabled
ls -ld -- $(cat filelist) # split+glob
Run Code Online (Sandbox Code Playgroud)
在 中zsh,你会这样做:
ls -ld -- ${(f)~"$(<filelist)"}
Run Code Online (Sandbox Code Playgroud)
f要在换行符上拆分的参数扩展标志在哪里,并~ 请求globbing,否则在参数扩展或命令替换时默认情况下不会执行此操作。
请注意,如果匹配文件的列表很大,您可能会遇到Argument list too long错误(execve()大多数系统上的系统调用限制),xargs否则本来可以解决的。在 中zsh,您可以zargs改用:
autoload zargs
zargs --eof= -- ${(f)~"$(<filelist)"} '' ls -ld --
Run Code Online (Sandbox Code Playgroud)
Wherezargs将拆分列表并运行ls多次以避免必要时的限制xargs。
或者您可以将列表传递给内置命令(因此不涉及execve()系统调用):
只打印文件列表:
print -rC1 -- ${(f)~"$(<filelist)"}
Run Code Online (Sandbox Code Playgroud)
或者将其提供xargs给以 NUL 分隔的:
print -rNC1 -- ${(f)~"$(<filelist)"} |
xargs -r0 ls -ld --
Run Code Online (Sandbox Code Playgroud)
请注意,如果任何 glob 无法匹配文件 in zsh,您将收到错误消息。如果您希望这些Nglob扩展为空,您可以将glob 限定符添加到 globs(nullglob在每个 glob 的基础上启用):
print -rNC1 -- ${(f)^~"$(<filelist)"}(N) |
xargs -r0 ls -ld --
Run Code Online (Sandbox Code Playgroud)
添加这(N)也会将所有没有 glob 运算符的行转换为 globs,允许过滤掉路径引用的文件和不存在的文件;但是,这意味着您不能在 glob 中使用 glob 限定符,filelist除非您将它们表示为(#q...)并启用该extendedglob选项。还要注意,由于限定符可以运行任意代码,因此filelist文件内容来自受信任的来源很重要。
在其他类似 Bourne 的 shell 中,包括bash,不匹配的 glob 将保持原样,因此将按字面传递给ls它,这可能会报告相应文件不存在的错误。
在 中bash,您可以使用该nullglob选项(它从 zsh 复制)并处理没有任何 glob 特别匹配的情况:
shopt -s nullglob
IFS=$'\n'
set +o noglob
set -- $(<filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
Run Code Online (Sandbox Code Playgroud)
bash,zsh的 glob 限定符没有任何等价物。为了确保没有 glob 运算符的行(例如您的/third/path/example.doc)被视为glob并在它们与实际文件不对应时被删除,您可以添加@()到行中(需要extglob)。但是,对于以/字符结尾的行,这将不起作用。但是,您可以添加@()到最后一个非/字符并依赖于/始终存在的事实
shopt -s nullglob extglob
IFS=$'\n'
set +o noglob
set -- $(LC_ALL=C sed 's|.*[^/]|&@()|' filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
Run Code Online (Sandbox Code Playgroud)
在任何情况下,请注意受支持的 glob 运算符列表随 shell 的不同而有很大差异。不过,您在示例中使用的唯一一个 ( *) 应该得到所有人的支持。
您可以稍微修改脚本,然后sh从xargs以下位置调用:
cat filelist | xargs -I{} sh -c 'ls $1' xargs-sh {}
Run Code Online (Sandbox Code Playgroud)
或者让我们xargs阅读文件本身:
xargs -a filelist -I{} /bin/sh -c 'ls $1' xargs-sh {}
Run Code Online (Sandbox Code Playgroud)