bash - 为什么 xargs 会在空格上拆分输入以及如何解决它?
问题描述
在以下bash
脚本中,我将文件列表从路径捕获到变量中,然后将其传递到xargs
以进行进一步操作。
我发现只需echo
对变量进行 ing,即可为每一行适当地添加空格,并为每一行添加一个换行符终止符。但是,当我printf
或echo
此结束时xargs
,我发现xargs
似乎也将每行的输入都用空格分隔。我将通过以下示例进行说明,其中包含我看到的结果的注释:
# Using GNU find:
list="$( find '$SOME_PATH' -type f )"
excluded_list="$( egrep -v -f FILE_WITH_PATTERNS_OF_FOLDERS_TO_EXCLUDE <<< $list )"
# This prints out just fine with lines such as "/some/path/here with spaces" on their own line, eg:
# /some/path/here with spaces
# /another/path/here with spaces
# /and yet another/path/here with spaces
echo "$excluded_list"
# But this prints out a line such as the above example "/some/path/here with spaces" broken up like this instead:
# /some/path/here
# with
# spaces
# /another/path/here
# with
# spaces
# /and
# yet
# another/path/here
# with
# spaces
printf "%s" "$excluded_list" | xargs -n 1 -P 1 sh -c 'echo "$0"'
# And the same result as `printf` above:
echo "$excluded_list" | xargs -n 1 -P 1 sh -c 'echo "$0"'
解决方案
将多个文件名分配给单个变量是一种反模式,因为除了空字节之外的任何特殊字符都可能出现在文件名中,并且您不能再次将变量拆分为原始文件名。
在您的示例echo "$excluded_list"
中可能看起来像保留原始文件名,但不幸的是它不是。尝试在路径名中插入两个或更多连续的空格,看看会发生什么。
作为急救,您可以$list
用双引号括起来,<<< "$list"
但这只是一种临时补救措施。
解决方法是:
- 将文件名存储在数组中
- 使用空字节作为分隔符并通过管道处理结果
例如,您可以这样说:
while IFS= read -r -d "" f; do
excluded_list+=("$f")
done < <(find "$SOME_PATH" -type f -print0 | egrep -v -z -Z -f FILE_WITH_PATTERNS_OF_FOLDERS_TO_EXCLUDE -)
for f in "${excluded_list[@]}"; do
echo "$f"
done
或者
find "$SOME_PATH" -type f -print0 | egrep -v -z -Z -f FILE_WITH_PATTERNS_OF_FOLDERS_TO_EXCLUDE - | xargs -0 -n 1 -P 1 sh -c 'echo "$0"'
请注意,-z
和-Z
选项是 GNU grep 的扩展,可能不适用于其他平台。
推荐阅读
- javascript - TouchableHighlight underlayColor 不起作用。颜色只是没有改变
- sql-server - 发送 SQL Server 命令以从 Access 移动数据(在服务器上)
- arrays - 在 BigQuery 中加入与选择数组
- rest - 调用休息服务时与 SSL 证书相关的问题
- git - 托管在 Bitbucket 上的 Git 存储库.. 计算我推送提交的每一天
- python-3.x - 覆盖类方法。打印输出,包括 NONE
- node.js - 如何将此 cURL 请求转换为节点请求调用?
- git - 如何从 Github 中的公共组织 repo 获取提交数量
- sql - 我正在使用带有存储过程的方法,但它总是返回 false
- html - 如何为 IE11 编辑网格模板列