帶有空格和特殊字元的 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(並且通配模式很可能擴展到多個檔案名稱),那麼可以使用單一命令將它們複製到某個目標目錄。


也可以看看:

相關內容