我有一个文件,其中每一行都是一个文件名。文件内容:
file1
file2
file3
...
然后我运行一个grep
命令来获取文件名列表的子集。
如何将grep
命令的输出输入到scp
?我尝试过xargs
但 $()
都没有成功...
答案1
无需使用xargs
:
for file in $(grep <some-pattern> <filelist>); do scp $file <remote>; done;
在哪里
<some-pattern>
是你的grep
模式<filelist>
是你的文件列表<remote>
scp
是你的命令的远程端
循环for
将遍历生成的每一行grep
并将其传递给,您可以在和$file
之间执行的命令中重复使用它。do
done
另请参阅:高级 Bash 脚本指南:循环
答案2
要迭代每行一个名称的文件名列表,您有几种可能性:
使用命令替换将文件放入 shell 中的文件名列表中。您需要采取预防措施,因为您不能将命令替换放在双引号中,因为命令替换的结果需要拆分为单词。您需要关闭通配符并设置为
IFS
仅在换行符上拆分单词。set -f; IFS=' ' scp -- $(…) remote.example.com:
使用
read
内置函数循环处理文件名。同样,您需要小心,因为它会特殊read
处理反斜杠和$IFS
字符。… | while IFS= read -r x; do scp -- "$x" remote.example.com: done
您可以使用 GNU xargs,但必须谨慎行事,因为 xargs 要求其输入采用奇怪的引用格式。您必须传递选项
-d '\n'
以明确选择换行符作为输入分隔符,并关闭空格和 的特殊行为\'"
。… | xargs -d '\n' -I {} scp {} remote.example.com:
的唯一优点
xargs
是它可以将多个参数组合到一次调用中,直到达到命令行长度限制,但这仅在参数最后传递给命令时才有效。您可以通过中间调用来实现这一点sh
,但这很少值得。… | xargs -d '\n' sh -c 'scp -- "$@" "$0"' remote.example.com:
一种更简单的使用方法
xargs
是获取以空字符分隔的列表,而不是以换行符分隔的列表。这需要选项-0
,GNU xargs 和最近的 *BSD 都支持该选项。如上所述,将参数推入非最终位置需要一些工作。… | tr '\n' '\0' | xargs -0 sh -c 'scp -- "$@" "$0"' remote.example.com:
如果您打算使用正则表达式过滤文件名,则该…
部分将起作用。如果您打算过滤文件内容,请使用上述技术之一将文件名提供给,例如grep NAME_REGEXP /path/to/filenames.list
grep
set -f; IFS='
'
scp -- $(grep -l CONTENT_REGEXP -- $(cat /path/to/filenames.list)) \
remote.example.com:
绕过 shell 困难的另一种可能性是使用rsync
及其--files-from
选项。假设文件名都是相对于当前目录的:
grep NAME_REGEXP /path/to/filenames.list |
rsync -a --files-from - . remote.example.com:
答案3
用于read
逐行解析输出(https://stackoverflow.com/a/7039208(英文):
grep <some-pattern> <filelist> | while read file; do scp $file <remote>; done;