使用 cp 和 grep 的详细 bash 脚本不适用于文件名中的空格

使用 cp 和 grep 的详细 bash 脚本不适用于文件名中的空格

我自己永远不会这样做,但使用 Windows 机器的人坚持在文件名中添加空格。

我已经编写了这个详细的命令,除了其中包含空格的文件之外,该命令运行良好。已经尝试过一切,单引号,双引号,勾号,用反斜杠转义。

该命令应该从具有特定文件扩展名的目录中复制所有内容,但我不想复制的文件列表除外。不幸的是,其中一些文件包含空格。这是命令:

cp $(ls *.txt *.docx | grep --invert-match --fixed-strings \
-e not_this_one.txt \
-e not_this_one_either.docx \
-e "no not me.txt" \
-e "please leave me out as well.docx")  ./destination_directory/

有什么想法可以让这项工作发挥作用吗?

答案1

使用findandxargs代替$(...)参数扩展:

find *.txt *.docx \( \
      -name not_this_one.txt \
      -o -name not_this_one_either.docx \
      -o -name 'no not me.txt' \
      -o -name "please leave me out as well.docx" \
    \) -prune -o -print0 |
  xargs -0 cp -t /tmp/destination_directory

我们使用该-prune选项来排除我们不想复制的内容。

我们使用-print0find 命令来生成以 NUL 结尾的文件名,当通过管道传输时,xargs -0该文件名可以正确处理包含空格的文件名。

最后,我们使用-t <target_directory>on 选项,cp因为这允许xargs将文件名列表附加到命令中(如果没有-t,目标目录需要放在最后,这会使事情变得有点复杂)。


或者,使用tar

tar -cf- \
    --exclude=not_this_one.txt \
    --exclude='not_this_one_either.docx' \
    --exclude='no not me.txt' \
    --exclude='please leave me out as well.docx' *.txt *.docx |
  tar -C /tmp/destination_directory -xf-

(当然,您可以将排除模式列表放入文件中并使用--exclude-from。)

答案2

一旦你发送ls *.txt *.docxtru 一个管道,|shell 就会生成一个字符串其中文件没有分开。好吧,它们可以用空格(或换行符)分隔,这会导致下一个尝试在空格(或换行符)上使用此类字符串拆分文件名的工具出现混乱。

由于您使用 bash 标记问题,glob 的扩展*.txt*.docx由 shell (bash) 完成的,并且 bash 能够拒绝 GLOBIGNORE 中给出的某些文件模式,因此您可以简单地执行以下操作:

( GLOBIGNORE='not_this_one.txt:not_this_one_either.docx:no not me.txt:please leave me out as well.docx';
  echo \
  cp -t /tmp/destination_directory *.txt *.docx
)

这里(...)是为了确保一旦子 shell 关闭,GLOBIGNORE 的设置就会被删除。当然,您可以将其删除并进行unset GLOBIGNORE后续操作。回显是为了向您显示命令的结果。如果您对所得到的结果感到满意,请消除回声。

相关内容