Bash 脚本:避免将单引号添加到字符串中

Bash 脚本:避免将单引号添加到字符串中

我正在尝试获取一个函数的输出并将其传递给另一个函数。

set -x
OUTPUT=$(git diff --name-only --diff-filter=AM develop... | sed 's/.*/"&"/')
./bin/phpcs $OUTPUT

我的主要问题是第一个函数返回文件列表,并且文件可能包含空格。因此,我将它们用双引号引起来,但是当我将其传递给其他函数时,会添加其他单引号。

输出:

++ git diff --name-only --diff-filter=AM develop...
++ sed 's/.*/"&"/'
+ OUTPUT='"test file.php"
"testfile.php"'
+ ./bin/phpcs '"test' 'file.php"' '"testfile.php"'

呼叫的主要最终目标等于:

./bin/phpcs "test file.php" "testfile.php"

答案1

您的问题是您正在向 输出的文本添加双引号git diff。这会破坏路径名,并使正确解析文件列表变得更加困难,特别是当任何路径名恰好包含引号时。

您在跟踪输出中看到的单引号只是添加了 ,bash以便更容易地查看字符串是如何分隔的(例如,显示"testfile.php"、 和"testfile.php"是三个单独的参数)。请记住,shell 的跟踪输出是调试输出,旨在提示您 shell 正在做什么,通常不是实际的由 shell 运行的代码。


要安全地使用输出的路径名git diff --name-only,请考虑使用该-z选项。这会导致git将路径名输出为空分隔列表。然后,您可以用来xargs -0对该列表的元素执行任何命令:

git diff --name-only -z --diff-filter=AM develop... |
xargs -0 ./bin/phpcs

您还可以将文件列表读入数组。例如,在bash外壳中:

readarray -d '' -t names < <( git diff --name-only -z --diff-filter=AM develop... )

./bin/phpcs "${names[@]}"

这显然依赖于git diff不输出太多名字

答案2

如果您可以保证文件名不包含换行符,您可以使用它们来分隔文件名并将它们弹出到数组中:

OIFS=$IFS IFS=$'\n'
files=( $(git diff --name-only --diff-filter=AM develop...) )
IFS=$OIFS

现在您可以将数组插入为带引号的字符串列表:

./bin/phpcs "${files[@]}"

这不会在 POSIXshdash.您需要使用bash支持数组的 shell

答案3

不添加单引号。bash -x只是向您显示看到了哪些字面参数。正如$OUTPUT未引用的那样,分词作用于空格和换行符。它们"是变量的一部分,与 shell 解析无关。

你可以这样做:

eval ./bin/phpcs $OUTPUT

不过,roaima 的数组方法似乎更好。

相关内容