我對 zsh 相當陌生(昨天從 bash 轉移)
我在 bash 中有一個 bash 函數,例如
vl() { cmd=`echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'`; vim $cmd }
這基本上轉換了一個參數,如:
vl ./manifests/production/test.pp:387:foobar # A output of $grep -iHn test
到
vim ./manifests/production/test.pp +387 #Aim is to open file at line-number 387
zsh 中的相同功能無法如預期般運作。它會開啟一個在 vim 中命名的文件./manifests/production/test.pp +387
,而不是開啟一個名為 的./manifests/production/test.pp
附加+387
文件。看起來,它正在將引號添加到$cmd
.
如果有人解釋這裡發生了什麼,那就太好了。謝謝
答案1
在普通的 Bourne 風格 shell 中,例如 Bourne shell、dash、ksh 和 bash,語法的$variable
意思是「獲取變數的值,將其拆分為IFS
出現字元的單獨單詞,並將每個單字視為檔案名稱通配符模式,並且如果它與多個文件之一匹配,則展開它」。如果variable
是數組,則這種情況發生在數組的第一個元素上,而其他元素將被忽略。
在 zsh 中,語法的$variable
意思是「取得變數的值,如果它為空則將其刪除」。如果variable
是一個數組,則該數組的所有元素都會發生這種情況。 Zsh 愛好者認為 zsh 方式更優越。
在 zsh 中,您可以編寫$=variable
來執行分詞。不過,這並不是做你正在做的事情的最佳方式。您的 bash 函數無法處理檔案名稱中的空格,並且$=variable
在 zsh 中使用也不會。這是一種不同的解析參數的方法,它適用於 bash 和 zsh,並且可以處理除:
檔案名稱之外的任何字元。如果參數包含兩個冒號,則刪除第一個冒號之後的所有內容,並將第一個冒號和第二個冒號之間的部分作為單獨的參數附加,前面加一個+
符號。它比您的程式碼稍長,但不那麼難以理解,而且它不會因為檔案名稱中的第一個空格提示而感到窒息。
vl () {
local suffix
case $1 in
*:*:*) suffix=${1#*:};; set -- "${1%%:*}" "+${suffix%%:*}";;
esac
vim "$@"
}
答案2
這是一個棘手的問題:) 一種解決方法是像這樣定義函數:
vl() { cmd=$(echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'); eval "vim $cmd"; }
請注意,解決方法是使用eval
,而不是我必須做的其他小修改,因為我缺少所需的 stackexchange editor-fu 8-)