击。逐行输出到另一个过程

时间:2015-05-26 12:20:32

标签: git bash

我有一个简单的GIT脚本: cp --parents $(git diff --name-only $1 $2) $3

git diff ... - 在提交之间获取修改的文件列表($ 1和$ 2)。

cp --parents ... - 将它们复制到所需目录($ 3)。

但唯一的问题是:目录名称中有空格。在这种情况下,脚本无法正常工作。显然,git diff输出的每一行都应该用引号括起来,但是如何?

还是有另一种解决方案吗?找不到它。

2 个答案:

答案 0 :(得分:4)

git diff支持-z选项,该选项将NUL分隔名称。然后,您可以通过xargs进行管道传输。例如:

$ git diff -z --name-only HEAD^ HEAD | xargs -I% -0 cp --parents "%" /tmp/

xargs的选项:

  • -0导致它期望输入数据被NUL分隔;
  • -I%使每个输入运行一次命令,并在命令行中用输入替换%(在Windows上显然是-i%?)。 %被任意选择,因为它很短,您也可以使用-IFOO / "FOO";
  • cp ...要执行的命令。

我使用/tmp/作为安全示例。

所以这应该有效地运行

$ cp --parents "file1" /tmp/

等等。或者,您可以在Bash中逐行读取git diff的输出。

$ git diff --name-only HEAD^ HEAD | ( while read fn ; do cp "${fn}" /tmp/ ; done )

答案 1 :(得分:2)

让我们在这里偏执,并以一种即使对非常不寻常/可能有恶意的文件名也有效的方式这样做:

while IFS= read -r -d '' filename; do
  cp --parents -- "$fn" /tmp/
done < <(git diff -z --name-only -- "$1" "$2")
  • 清除IFS(IFS= read)可防止名称中的尾随空格被剥离。
  • 使用-r参数read可以防止文件名中的文字反斜杠被删除,从而被剥离。
  • 使用diff -zread -d '' NUL分隔名称; NUL是POSIX文件名中唯一不存在的字符。
  • --使cp将文件名视为文件名,即使它们以-字符开头,否则将被视为选项。同样适用于git diff
  • 使用< <(...)构造而不是将while循环放在管道的右侧意味着如果您愿意,可以在循环内设置变量,这些变量仍然会以后存在。

有人发现某些版本的msys运行时环境(特别是包含Windows的“git bash”附带的版本)不支持进程替换。因此,可能有必要使用管道(包含所有caveats this implies):

git diff -z --name-only -- "$1" "$2" |
  while IFS= read -r -d '' filename; do
    cp --parents -- "$fn" /tmp/
  done