带有空格和特殊字符的 cp 在终端上工作正常,但在脚本中却不行

带有空格和特殊字符的 cp 在终端上工作正常,但在脚本中却不行

我正在尝试编写一个脚本来查找文件并将其复制到特定文件夹。文件名包含空格和其他特殊字符。

a=$(ls ~/Downloads/ | grep $1)
a="'$a'"
a="~/Downloads/"$a
echo $a
cp $a ~/Documents/books/.

当我引用文件名时,它在终端上运行良好。但在脚本中,这些词被视为单独的参数。在上面的脚本中,当 $a 被回显时,它会给出如下内容:

~/Downloads/'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

您可以看到文件名被引用。当上述参数传递给终端上的 cp 时,它可以正常工作,但在脚本上却不行。请帮忙。

答案1

您似乎想要将特定文件从~/Downloads复制到~/Documents/books

首先要注意的是它~不表现为变量。特别是,它确实不是引用时扩展到主目录的路径。因此,在脚本中,最好使用$HOME来引用主目录。

第二件事是您似乎在变量的值中添加了单引号$a。这是不必要的,只会导致“没有这样的文件或目录”错误(因为该文件的文件名中没有单引号)。

第三件事是你应该尽量避免ls在脚本中使用。例如,在这种情况下,if$1只是文件名,~/Downloads您根本不必搜索它。此外,grep $1由于多种原因,使用也存在问题:

  • grep主要用于文本文件。理论上,文件名可能包含换行符,这使得“grepping”文件名只有在知道名称或“好”的情况下才有效。
  • $1未加引号,因此grep如果它包含空格或其他特殊字符,可能会造成混淆。例如,如果$1是,它将扩展到当前目录中的所有文件名。*
  • 如果字符串$1以破折号开头,它将被视为 的选项grep

所以,你的脚本可以写成

#!/bin/sh

name="$HOME/Downloads/$1"

printf 'The filename is "%s"\n' "$name"

cp "$name" "$HOME/Documents/books"

这里的命令printf是输出我们选择的文件的名称。我是输出名称周围有双引号,但名称确实不是里面有双引号。相反,我确保 在最后一行的$name调用中引用。cp事实上,我一定要引用全部我知道扩展否则会导致 shell 分割变量的值。

您可以将该脚本用作

./script.sh 'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

文件名必须加引号,因为它包含 shell 中特殊的空格和字符。

如果您希望脚本查找包含命令行上给出的单词的文件,那么您可以说

./script.sh Goodfellow

然后以通配模式使用给定的字符串:

#!/bin/sh

for name in "$HOME/Downloads"/*"$1"*.pdf; do
    printf 'Will copy the file "%s"\n' "$name"
    cp "$name" "$HOME/Documents/books"
done

现在,脚本将采用第一个参数并循环遍历文件名中包含给定字符串的所有.pdf文件。~/Downloads每个这样的文件都将被复制到~/Documents/books.

如果您使用的是 Unix,cp -v将详细复制文件,则脚本可能会进一步缩小:

#!/bin/sh

cp -v "$HOME/Downloads"/*"$1"*.pdf "$HOME/Documents/books"

这可以防止您自己格式化输出(“将复制...”),因为我们不再循环匹配给定模式的文件名。相反,我们只是依赖这样一个事实:如果您给定多个文件名cp(并且通配模式很可能扩展到多个文件名),那么可以使用单个命令将它们复制到某个目标目录。


也可以看看:

相关内容