检查文件是否存在后如何将文件名列表传递给 xargs?

检查文件是否存在后如何将文件名列表传递给 xargs?

我有一个命令 ( 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[@]}"))"

(这里假设ksh93zshbashmkshyashshell)。

相关内容