我只是偶然發現在 bash 中,我們可以將命令分配給變數而不使用alias
.
g=date
$g
Mon Jun 27 13:00:40 MYT 2016
這樣可行。這是另一個例子:
jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms
我正在使用這個版本的bashbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
我已經調查過堆疊交換和tldp 吸收值,但沒有發現我們可以這樣做。那麼這是 bash 的新功能還是被忽略的東西呢?這是否被考慮命令替換?
答案1
在互動式使用中,外殼從終端設備讀取輸入行。輸入一行後,就是解析的透過分裂成代幣(單字和運算符)。然後以特定順序擴展或解析標記或單字。
注意:一般來說,通常最好參考規範的資訊來源,例如專案文件或行業規範,而不是二手來源,例如高級 Bash 腳本指南、線上教學、書籍 - 甚至 Stack Exchange :)。此類二手資料對於用更簡單的語言介紹和解釋概念很有用,但它們通常並不旨在完整或取代官方文件。二手來源中的資訊也可能已經過時。
在這種情況下,解析簡單指令的 POSIX 規範指出
- 不是變數賦值或重定向的單字應該被擴展。如果擴充後仍有任何字段,則第一個字段應被視為命令名稱,其餘字段是命令的參數。
- 不是變數賦值或重定向的單字會被擴展(請參閱 Shell 擴充)。如果擴展後仍有任何單詞,則第一個單字將被視為命令名稱,其餘單字將被視為參數。
答案2
這不是命令替換,而是多變的代換。您不是將命令分配給變量,而是分配一個字串。該命令在您使用變數時運行,而不是在賦值時運行。
g=date
將字串儲存date
在變數中g
。如果您隨後運行echo "$g"
,則會列印 的值g
,即date
(後面跟著換行符),因為 的值會作為第一個參數g
傳遞給命令。echo
如果運行"$g"
,這會將字串date
放在命令的第一個位置,因此它是命令名稱。
和$jj
,第二個因素開始發揮作用。因為變數擴展是在引號之外,所以“split+glob 運算子”應用於該值。在本例中,這表示 的值jj
被分成兩個以空格分隔的單字。因此,該單字ping
最終位於命令位置,並且該單字yahoo.com
是第一個參數。
答案3
這是預期的行為,並且多年來一直有效。它對於在腳本中建置命令很有用。
例如,我有時應該在將某些輸入發送到管道之前對其進行解壓縮(然後對輸出進行壓縮),但有時則不然。使用bash
:
if (( use_compression == 1 )); then
infilter='gzip -d -c'
outfilter='gzip -c'
else
infilter='cat'
outfilter='cat'
fi
$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"
是命令替換嗎?不$(...)
。
這是相反參數擴充,即簡單地將參數替換為其值。這發生在命令實際執行之前,這就是它起作用的原因。
這意味著像下面這樣的東西也可以在命令列上運行:
$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename
(這會執行gunzip
而不是gzip
)
編輯:關於別名。
手冊bash
說:
幾乎所有用途,別名都被 shell 函數取代。
.... 並且我同意。
別名適合簡短的內容,例如
alias ls="ls -F"
(這是我在自己的 shell 會話中擁有的唯一別名)
您可能不想在命令列上對“別名”命令使用參數擴展。如果沒有其他原因的話,打字會讓人感到脖子疼痛。參數擴充也不允許執行稍微複雜的任務,例如管道。
如果您定期執行中等複雜的操作,請改用 shell 函數。
以已接受的答案為例U&L問題(您在下面的評論中連結到):
alias my_File='ls -f | grep -v /'
這個別名顯然有效,但是使用
my_File='ls -f | grep -v /'
$my_File
如果您隨後嘗試在命令列上用作命令,則該命令將無法運作(如該 U&L 線程中所解釋的原因)。
使用 shell 函數,您還可以執行諸如傳遞參數之類的操作:
function my_File {
ls -l "$@" | fgrep -v '/'
}
$ my_File -iF symlink
84416642 lrwxr-xr-x 1 kk staff 4 Jun 27 09:03 symlink@ -> file
答案4
它只是使用 shell 變量,這個概念已經存在並像這樣工作了幾十年(這並不誇張)。
當您將變數放入命令列時,shell 會取代它,然後執行該命令,因此如果您的變數位於開頭,那麼它顯然會被視為命令。