我正在尝试编写一个脚本来查找文件并将其复制到特定文件夹。文件名包含空格和其他特殊字符。
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
(并且通配模式很可能扩展到多个文件名),那么可以使用单个命令将它们复制到某个目标目录。
也可以看看: