gpt4 book ai didi

bash - 如何引用命令替换以使其表现得像 "$@"?

转载 作者:行者123 更新时间:2023-11-29 09:37:34 26 4
gpt4 key购买 nike

$* 等同于 $1 $2 $3... - 在所有空格处拆分。

"$*" 等同于 "$1 $2 $3..." - 此处不拆分。

"$@" 等同于 "$1""$2""$3"... - 拆分参数(每个参数都单独引用)。

如何引用 $(command) 以便它以与 "$@" 处理参数相同的方式处理命令的输出行?

我要解决的问题:

我有一个备份功能,它通过参数获取文件并备份每个文件(例如:backup file1 file_2 "file 3")。我想快速备份另一个命令返回的文件。

mycmd 返回三个文件(每行一个):file1file_2file 3(包含一个空间)。如果我运行以下命令:

backup $(mycmd)

这相当于运行 backup file1 file_2 file 3 并且会因为不存在的文件 file3。但是以这种方式运行它:

backup "$(mycmd)"

相当于运行:

backup "file1file_2file 3"

它们都不够好。

我如何使用命令替换来获取等效于以下内容的调用:backup "file1""file_2""file 3"

目前我唯一的解决方法是:

while read line; do backup "$line"; done < <(mycmd)

最佳答案

文件名列表(或命令行参数)不能在不转义的情况下以面向行的格式安全地传递。

这是因为命令替换计算为 C 字符串。 C 字符串可以包含 NUL 以外的任何字符。

您的预期用例是生成文件名列表。单个文件名可以包含 NUL 以外的任何字符(也就是说:流行操作系统上的文件名允许包含文字换行符)。

对于其他命令行参数也是如此:foo$'\n'bar 作为参数列表元素是完全有效的。

因此,实际上不可能(不使用商定的转义机制或一个工具知道如何生成而另一个工具知道如何解析的更高级格式)在命令替换的输出中表示任意文件名。


将文件名列表安全地处理为字符串

如果您希望流安全地包含任意文件名列表,它应该以 NUL 分隔。例如,这是 find -print0 或简单命令 printf '%s\0' * 生成的格式。

但是,您不能将其读入 shell 变量,因为(同样)shell 变量不能包含 NUL 字 rune 字。您可以做的是将其读入数组:

files=( )
while IFS= read -r -d '' filename; do
files+=( "$filename" )
done < <(find . -name '*.txt' -print0 )

然后展开那个数组:

backup "${files[@]}"

安全地处理面向行的内容(已知不包含换行文字)

如上所述,您可以将一系列行读入一个数组,然后扩展该数组(但对于这里的情况不安全,数据是任意文件名):

# 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[@]}"

将正确发出:

Was passed argument: <first line>
Was passed argument: <second line>
Was passed argument: <third line>

关于bash - 如何引用命令替换以使其表现得像 "$@"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45359853/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com