我正在嘗試編寫一個腳本來查找文件並將其複製到特定資料夾。檔案名稱包含空格和其他特殊字元。
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
(並且通配模式很可能擴展到多個檔案名稱),那麼可以使用單一命令將它們複製到某個目標目錄。
也可以看看: