我有一个命令 ( command1
) 返回文件名列表,如下所示
/consumer/a.txt
/consumer/b.txt
/consumer/doesnotexist.txt
当我通过管道输出时,command1 | xargs command2
command2
如果其中一个文件不存在,则会引发异常。
如何在将不存在的文件通过管道传输到 之前删除它command2
?我期待以下内容
command1 | xargs remove_nonexistant_files | xargs command2
command2
应该收到
/consumer/a.txt
/consumer/b.txt
作为输入。
答案1
command1 |
xargs sh -c 'for p do [ -f "$p" ] && printf "%s\n" "$p"; done' sh |
xargs command 2
中间的额外位是xargs
对一个短脚本的另一个调用,该脚本基本上只是循环其给定的命令行参数并打印与现有常规文件(或常规文件的符号链接)相对应的路径名。然后,这些现有路径名将传递到管道的最后部分。
这假设所有路径名都没有嵌入的换行符、空格和制表符。
答案2
假设command1
以 期望的格式输出列表xargs
,您可以定义:
existing_plain_readable_files_only() {
perl -le "for (@ARGV) {
if (-f && -r) {s/'/'\\\\''/g; print qq('\$_')}
}" -- "$@"
}
并将其用作:
command1 | xargs existing_plain_readable_files_only | xargs command2
在这里,我们使用perl
's-f
运算符常规的仅文件(不是目录、设备、管道...)以及-r
那些可读的由用户(假设command2
想要阅读它们),我们使用单引号引用,但单引号字符本身除外,单引号字符本身用 转义\
。
xargs
这是shell 都支持的一种引用,这意味着您还可以使用该函数来处理包含任意文件列表的 shell 数组:
eval "array2=($(existing_plain_readable_files_only "${array1[@]}"))"
(这里假设ksh93
、zsh
、bash
、mksh
或yash
shell)。