無法 cd 到 bash 腳本中的(傳遞的)變數

無法 cd 到 bash 腳本中的(傳遞的)變數

我正在使用 bash 從 audacious 到 conky 獲取一些資訊以供顯示(包括專輯封面)。我從 audacious 獲取音樂檔案目錄的路徑,然後嘗試 cd 到該目錄以查找folder.jpg - 如果找到,則準備顯示。不幸的是不能依賴「格式良好」的路徑名。它們都沒有來自終端的問題,但是 bash 的評估...它被雙倍空格 ( ) ' / 以及其他可能的空格阻塞,儘管當前的設置似乎可以處理 - 好的。這是相關的功能:

GetArt ()
{
    file_path=`audtool --current-song-tuple-data file-path` # get the path to the song
    file_path=$(eval echo "${file_path}")                   # pre-expand to full path
    cd "${file_path}"
    if [[ ! -e "folder.jpg" ]];                             # if no art work found
    then
        cp ~/Work/vinyl.png /tmp/cover.png              # put in placeholder
    else
        convert "${file_path}""/folder.jpg" -resize 120x120 /tmp/cover.png # ready for showing
    fi
}

有什麼想法,或者拿出鋼絲刷並從我的“C”編譯器中去除鐵鏽會更容易嗎?

我嘗試使用雙引號、單引號、反引號,甚至是這樣的結構:

code=$code \"\$filename\""

但到目前為止似乎還沒有什麼能正常運作。幸運的是,它失敗了“漂亮”,因為它只是彈出“找不到藝術”替代圖片,但有時事情會在標準錯誤中打嗝,直到下一首歌曲或專輯。

答案1

您可以使用file_path="${file_path/#~/$HOME}"來擴展只是~

據我所知,波形符擴充是唯一需要對 的輸出執行的擴展audtool --current-song-tuple-data file-path。此外,僅出現一種波浪號表示法的特定情況:如果 Audacious 正在使用的路徑以運行 Audacious 的使用者的主目錄開頭,則路徑的該部分將~在 的輸出中替換為audtool。自從audaciousaudtool手冊頁沒有澄清這一點,我試圖獲取以波浪號擴展audtool形式為前綴的輸出路徑~username,幸運的是,它似乎永遠不會這樣做。我說「幸運」是因為這意味著情況非常簡單。

由於該命令的輸出需要完成的唯一轉換audtool是將前導替換~為使用者主目錄的路徑,因此您可以簡單地在腳本中編寫程式碼來執行該擴充功能本身,否則保留路徑不變。您發現您可能播放的音訊檔案的檔案名稱可能包含經過 shell 特殊處理的字符,並且如果您播放其他人命名的文件甚至可能引發安全漏洞在你的腳本中。透過不讓 shell 執行(甚至展開)任意的、不受信任的文本,您可以完全避免該問題。

有多種方法可以擴展~自己。我建議:

file_path="$(audtool --current-song-tuple-data file-path)"  # might need tilde expansion
file_path="${file_path/#~/$HOME}"  # do the tilde expansion, if needed

這將手動執行可能需要的一種轉換。具體來說,當 的輸出audtool以 a 開頭時~,會將其替換為透過檢查變數值而獲得的使用者主目錄HOME。當輸出不以 a 開頭時~,不執行擴展。

請注意,這種方法 ,${file_path/#~/$HOME}不是如果它被用作模擬所有形式的波形符擴展的嘗試,那麼它是正確的,因為它會在形式~username(以及其他一些更模糊的形式)中執行不正確的替換。但是,只要輸出中的路徑audtool僅在指定當前用戶主目錄的簡單情況下使用波浪號表示法(我相信是這種情況),那麼這種方法對於這些路徑來說是適當且正確的。

它的運作方式是:

  • 一般來說,Bash 將擴展 ${parameter/pattern/string}的值parameter,但與匹配的部分pattern替換為string.如果沒有部分與模式匹配,則parameter使用 的精確值。
  • pattern帶有前導時#,只能從 值的最開頭開始匹配parameter。 (除此之外還有其他字元#在此位置有意義:a%需要在最開始匹配模式結尾,並且 a/會導致模式被匹配和替換多次,而不是最多一次。
  • ~在模式中沒有特殊含義,因此按字面意思處理,作為要匹配和替換的字元。

參數擴充了解詳情。

請注意,我編寫的程式碼不會執行任何操作來處理產生空輸出的情況audtool,就像當前沒有播放歌曲時發生的情況(或者,如西蒙·薩德勒提到,如果有錯誤)。但是,它不會在空輸出時中斷或妨礙後續處理。因此,如果您想承保這種情況,您仍然可以。

最後,我應該提到,我忽略了兩個我認為對您的用例不重要的區別:

  1. 由於audtool的路徑來自 Audacious,如果您嘗試以一個用戶身份運行 Audacious 並audtool以另一個用戶身份運行這種奇怪的情況(並且您以某種方式配置了D-Bus,以便可以正常工作),那麼您將不得不關心~引用不同的使用者使用者的主目錄而不是執行腳本的使用者的主目錄。
  2. 從技術上講,當前用戶的波形符擴展(發生在 shell 中,其~本身或緊隨其後/)不是相當相當於"$HOME"。外殼可能會嘗試處理HOME未設定的奇怪情況。 Bash 確實嘗試處理這個問題並且仍然產生正確的擴展。不過,我懷疑你是否在乎這個目的的差別。看波形符擴充了解詳情。

答案2

file_path不需要重新分配變數。有兩種可能發生的跡象可能會破壞腳本:

  1. 變數為空,因為audtool回傳錯誤
  2. 傳回audtools一個目錄,其中包含空格。
  3. audtool包含~主目錄

這裡有一個關於如何解決這些問題的建議:

GetArt ()
{
    file_path="$(audtool --current-song-tuple-data file-path)"
    file_path="$(readlink -f "$(bash -c "echo $file_path")")"
    if [[ ! -d $file_path ]]; then
        echo "error: $file_path does not exists"
        exit 1
    fi
    folder_jpg="$file_path/folder.jpg"
    if [[ ! -e "$folder_jpg" ]]; then
        cp ~/Work/vinyl.png /tmp/cover.png
    else
        convert "$folder_jpg" -resize 120x120 /tmp/cover.png
    fi
}

處理"$(command)"資料夾名稱中的空格(如果有)。cd如果不需要,請勿在腳本內部使用。檢查返回字串是否是目錄始終是一個好主意。在大多數情況下,使用絕對路徑會更好,並且可以防止在錯誤的資料夾中執行命令。

~bash 中擴展的注意事項:

的擴展~由 bash 處理,因此readlink -f在這裡沒有幫助。因此,包含 的變數~必須在不加引號的情況下執行才能擴展(我更新了腳本)。這當然可以在一行中處理......

# expansion from current bash
$ set -x; readlink -f ~; set +x
+ readlink -f /home/user
/home/user
+ set +x

# expansion will not work, with quoted ~
$ set -x; readlink -f '~'; set +x
+ readlink -f '~'
/home/user/~
+ set +x

# expansion from un-quoted ~ with sub-shell
$ set -x; readlink -f "$(bash -c "echo ~")"; set +x
++ bash -c 'echo ~'
+ readlink -f /home/user
/home/user
+ set +x

相關內容