2010-06-28 71 views
5

在BASH腳本中,我試圖檢測文件是否存在。文件名在變量中,但-e命令似乎無法檢測到該文件。下面的代碼始終輸出「〜/其它/任務/ drupal_backup.sh不存在」Bash腳本-e未檢測到變量中的文件名

filename="~/misc/tasks/drupal_backup.sh" 

if [ -e "$filename" ]; then 
    echo "$filename exists" 
else 
    echo "$filename does not exist" 
fi 

在另一方面,下面的代碼檢測正確的文件:

if [ -e ~/misc/tasks/drupal_backup.sh ]; then 
    echo "$filename exists" 
else 
    echo "$filename does not exist" 
fi 

爲什麼會變成這樣?當文件名位於變量中時,如何才能檢測文件?

+1

我認爲'〜'是一個不應該在腳本中使用的命令行便利。 – 2010-06-28 03:20:14

回答

7

這是一個有趣的。將$HOME替換爲~的作用與刪除作業中的引號一樣有效。

如果您將set -x置於該腳本的頂部,則會看到帶引號的版本將文件名設置爲~/...,這是給-e的內容。如果刪除引號,文件名將被設置爲擴展/home/somebody/...。因此,在第一種情況下,您會看到:

+ [ -e ~/... ] 

並且它不喜歡它。在第二種情況下,您會看到:

+ [ -e /home/somebody/... ] 

,它確實工作。

如果你做到這一點沒有變,你看:

+ [ -e /home/somebody/... ] 

,是的,它的工作原理。


有點調查後,我發現,它實際上是在bash執行其擴展的順序。從bash手冊頁:

擴展的順序是:括號擴展,代字符擴展,參數,變量和算術擴展和命令替換(按照從左到右的方式完成),單詞分割和路徑名擴張。

這就是爲什麼它不工作,變量替換代字號擴展。換句話說,在bash想要擴大~的地方,沒有一個。只有在變量擴展之後,單詞纔會變成~/...,之後就不會有代字符擴展。

有一件事你可能是改變你的if聲明:

if [[ -e $(eval echo $filename) ]]; then 

這兩次評估$ filename參數。第一次(eval),在波浪擴展階段期間不會有~,但$filename將在可變擴展階段更改爲~/...

然後,在第二次評估時(作爲if本身的一部分完成的評估),~將在代字號擴展階段出現。

我測試過我的.profile文件,它似乎工作,我建議您在您的具體情況確認。

+0

謝謝!用$ HOME替換〜完美無缺。 – thornate 2010-06-28 03:24:01

+1

應該指出,你不應該使用'eval'。 「〜〜」是交互模式的一個很好的縮寫,但是應該在腳本中避免出現這個原因。很多初始化腳本包含諸如'[-r〜/ .profile] &&之類的東西。 〜/ .profile',我不知道這是否適用於主目錄中包含空格的情況。最好使用$ HOME並引用所有變量:'filename =「$ HOME/misc/tasks/drupal_backup.sh」'。在這種情況下,引號不是必需的,但它不是有害的,只需引用所有內容就更容易了,除非您確切知道可以在哪裏刪除引號。 – Philipp 2010-06-28 05:57:06

+0

@Phillipp,如果你打算在一個精英團體中做一個像「你永遠不應該使用eval」的總括性陳述,你可能想考慮將它與你的推理結合起來:-) – paxdiablo 2010-06-28 06:14:34