无法使用 rm 删除名称上有空格的多个文件

无法使用 rm 删除名称上有空格的多个文件

我正在为我的点文件编写一个部署脚本,它们存储在一个 Git 裸存储库中,我将git checkout文件从该存储库存储到我的主目录中,为了无缝地完成它而不会出现数千个 Git 签出错误,我必须删除已经存在的那些(.bashrc例如),我实际上是用以下命令检索它们

git --git-dir=$HOME/repos/dots --work-tree=$HOME ls-tree --full-tree --full-name --name-only -r HEAD | sed "s|^|/mnt/home/henriquehbr/|"

注意:原因是/mnt它是我的 chroot 安装的挂载点,我实际上是从我的自定义 Arch Linux 安装映像运行它

但是当涉及到实际删除这些文件时,我没有成功,问题在于名称中包含空格的文件(Font\ Awesome\ Icons.otf例如)

我尝试通过将上面的命令传递到以下命令序列来引用要删除的每个文件:

<get_dotfiles> | sed "s|^|\"/mnt/home/henriquehbr/|" | sed "s/$/\"/"

上面的方法不起作用,我认为rm按字面意思对待引号,就好像它们是文件名的一部分一样

其他尝试是通过制作一个好的循环for

dotfiles=$(git --git-dir=$HOME/repos/dots --work-tree=$HOME ls-tree --full-tree --full-name --name-only -r HEAD | sed "s|^|/mnt/home/henriquehbr/|")

for dotfile in $dotfiles; do
    echo "$dotfile" # Works properly, displays dotfile path
    rm "$dotfile" # Doesn't works, writes: '$'\n'' after the path and fails
done

答案1

使用空字节作为分隔符:

git ls-tree -z … | xargs -0 rm

请注意,在大多数 shell 中,您不能将空字节放入变量中,因此$(git ls-tree -z …)不会执行任何有用的操作。

如果您尝试使用引号导致将引号传递给 ,则不会起作用rmrm与大多数程序一样,只需要文件名。对于它来说,"是一个普通字符,就像文件名中出现的任何其他字符一样。注入引号也无助于 shell 中的替换:不带引号的变量替换或命令替换 ($foo$(mycommand …)) 只是在空格处分割(然后将每个单词视为通配符模式),引号在此阶段不相关。如果文件名本身不包含太“异国情调”的字符(例如反斜杠、制表符、双引号等),则注入引号并传递给xargs(不带) 可以起作用,但它比使用and复杂得多。-0git ls-tree -zxargs -0

假设文件名不包含任何git ls-tree本身引用的字符(包括换行符),这将起作用(再次,不干扰引号):

set -f # disable wildcard expansion (globbing)
IFS='
' # set only newline as the word separator
for dotfile in $(git ls-tree …); do … 

这并不是一个好主意。如果你只是想在运行时强行删除现有文件git checkout,Git 会很乐意删除运行时的文件git checkout -f …。签入现有文件会更安全,以防它们包含重要内容。

git checkout -b original-files
git --git-dir=… ls-tree -z | xargs -0 git add
git commit -m "Original files on $HOSTNAME"
git checkout origin/master

答案2

实际上,我最终得到了一种更简单的解决方案,不需要所有这些复杂性,一个简单的“强制”git checkout 就可以在部署过程中替换我所有旧的点文件:

git checkout -f

道具先生不是先生红迪网

相关内容