Pio*_*otr 2 bash quoting command-substitution
$*相当于$1 $2 $3...- 拆分所有空格.
"$*"相当于"$1 $2 $3..."- 这里没有分裂.
"$@"相当于"$1" "$2" "$3"...- 分裂参数(每个参数单独引用).
如何引用$(command) 以便它以相同的方式"$@"处理命令的输出行来处理参数?
我想解决的问题:
我有一个备份函数,通过参数获取文件并备份每个文件(例如:) backup file1 file_2 "file 3".我想快速备份另一个命令返回的文件.
mycmd返回三个文件(每行一个):file1,file_2和file 3(包含空格).如果我运行以下命令:
backup $(mycmd)
它将等同于运行,backup file1 file_2 file 3并且由于不存在的文件和3而导致错误.但是这样运行:
backup "$(mycmd)"
相当于运行:
backup "file1 file_2 file 3"
它们都不够好.
如何使用命令替换来获得相当于的调用:backup "file1" "file_2" "file 3"?
目前我唯一的解决方法是:
while read line; do backup "$line"; done < <(mycmd)
这是因为命令替换计算为C字符串.AC字符串可以包含除NUL之外的任何字符.
您的预期用例是生成文件名列表.单个文件名还可以包含除NUL之外的任何字符(也就是说:允许流行操作系统上的文件名包含文字换行符).
对于其他命令行参数也是如此:foo$'\n'bar作为参数列表元素完全有效.
因此,在命令替换的输出中表示任意文件名,因此几乎不可能(不使用商定的转义机制或更高级别的格式,一个工具知道如何生成,另一个知道如何解析).
如果您希望流安全地包含任意文件名列表,则应该以NUL分隔.这是由find -print0例如简单命令产生的格式printf '%s\0' *.
但是,您无法将其读入shell变量,因为(再次)shell变量不能包含NUL字符文字.你可以做的是把它读成一个数组:
files=( )
while IFS= read -r -d '' filename; do
files+=( "$filename" )
done < <(find . -name '*.txt' -print0 )
Run Code Online (Sandbox Code Playgroud)
然后展开该数组:
backup "${files[@]}"
Run Code Online (Sandbox Code Playgroud)
如上所述,你可以将一系列行读入一个数组,并展开该数组(但这里的情况并不安全,数据是任意文件名):
# readarray is a bash 4.0 builtin
readarray -t lines <(printf '%s\n' "first line" "second line" "third line")
printf 'Was passed argument: <%s>\n' "${lines[@]}"
Run Code Online (Sandbox Code Playgroud)
将适当地发出:
Was passed argument: <first line>
Was passed argument: <second line>
Was passed argument: <third line>
Run Code Online (Sandbox Code Playgroud)