无法将包含空格的文件添加到Git

4

我正在编写一个脚本,使用git add .命令添加未被跟踪的文件。 我在脚本中使用的循环代码是:

for FILE in $(git ls-files -o --exclude-standard); do  
git add $FILE  
git commit -m "Added $FILE"  
git push origin master  
done 

这个脚本在遇到有空格的文件名时会出现问题。例如,我不能添加文件Hello 22.mp4。(请注意,Hello和22之间有一个空格)。上面的循环将把该文件视为2个单独的文件,Hello22.mp4,并因错误退出。

有人知道如何将其作为单个文件添加吗?
谢谢


@SiegeX 谢谢你的提示。我之前不知道这个,我一定会改正的。 - harithahv
@BasileStarynkevitch:这是一个有点愚蠢的规则。文件系统支持它。因此,您应该编写处理这种(完全有效)用例的脚本,而不是假装它不存在。 - AndrewF
Linux Ext3文件系统还支持在文件名中使用控制字符(除了空字符和斜杠)。但这并不意味着我们应该使用它们,因为只有少数脚本能够处理所有这些字符。更合理的做法是避免使用它们(即使从理论上讲它们应该是可行的)。 - Basile Starynkevitch
嗯...我考虑了一下并尝试了一下,但由于某些原因(我不记得了——那是很久以前的事了),它没有起作用...也许有人能指出是什么问题! - harithahv
http://mywiki.wooledge.org/ParsingLs - Samus_
显示剩余3条评论
6个回答

10

所发生的是shell正在将$(...)展开为一堆单词,而包含空格的文件显然被解释为多个文件。即使之前建议对git add命令加上引号,也无法解决这个问题。因此,循环正在使用错误的参数运行,如使用set -x命令显示的输出所示:

ubuntu@up:~/test$ ls -1
a a
ubuntu@up:~/test$ set -x; for FILE in $(git ls-files -o --exclude-standard); do git add "$FILE"; git commit -m "Added $FILE"; done
+ set -x
++ git ls-files -o --exclude-standard
+ for FILE in '$(git ls-files -o --exclude-standard)'
+ git add a
...

正确的解决方法是对 git add $file 进行引用,并使用 git ls-files-z 选项将文件名以 NULL 分隔,然后使用一个带有 null 分隔符的 while 循环:

git ls-files -o --exclude-standard -z | while read -r -d '' file; do
  git add "$file"
  git commit -m "Added $file"
  git push origin master
done

嘿..成功了..谢谢AndrewF..这对我来说意义重大..我是一个在这里尝试学习脚本编程的新手..你能帮我理解一下它的工作原理吗?为什么我们要使用管道、-z和while呢?难道第一行不需要一个'for'循环吗? - harithahv
对于这种情况,你不能使用for循环。子shell($())将“a.txt”、“b a.txt”转换为“a.txt b a.txt”,而for循环不知道b和b.txt是相同的。你必须使用不同于空格的分隔符。空分隔符被用作替代,更何况它总是比假设文件不包含空格更安全。因为你不能使用for循环,所以必须使用while read。你会发现,“find”命令和“xargs”都支持NULL分隔的输入。别忘了接受你选择的答案。 - AndrewF
你还需要使用read清除IFS,像这样: while IFS= read -r -d '' file; do ... done。否则,任何前导和尾随空格都将被删除。 - musiphil

4
如果您正在使用bash替代@AndrewF提供的解决方案,您可以利用IFS bash内部变量将分隔符从空格更改为换行符,类似于以下内容: IFS
(IFS=$'\n'
for FILE in $(git ls-files -o --exclude-standard); do  
git add $FILE  
git commit -m "Added $FILE"  
git push origin master  
done 
)

这只是提供给您的信息。AndrewF的回答更加详细,涵盖了调试选项和while循环而不是for循环的用法。
希望这能有所帮助!


2
尝试将$FILE变量用引号括起来:

git add "$FILE"

这将引用文件名,从而允许其中包含空格。


嗯...这看起来是个好主意...但即使尝试使用"$FILE",我仍然收到相同的错误消息...这意味着git没有跟踪该文件... - harithahv

1

git add $FILE替换为git add "$FILE"。这样它将被解释为单个元素。


0

如果要将单个文件添加,请在文件名中的空格前加上反斜杠:

git add pathtofilename/filenamewith\ space.txt


0

我知道这已经很晚了,但是这里有一种使用标准xargs Linux命令的方法:

git ls-files -o --exclude-standard | xargs -L 1 -I{} -d '\n' git add '{}'

您可以通过以下方式简单地回显命令来测试它:

git ls-files -o --exclude-standard | xargs -L 1 -I{} -d '\n' echo "git add '{}'"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接