將命令分配給沒有別名的變數

將命令分配給沒有別名的變數

我只是偶然發現在 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 規範指出

  1. 不是變數賦值或重定向的單字應該被擴展。如果擴充後仍有任何字段,則第一個字段應被視為命令名稱,其餘字段是命令的參數。

Bash 手冊中簡單指令擴充的部分也指出

  1. 不是變數賦值或重定向的單字會被擴展(請參閱 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 會取代它,然後執行該命令,因此如果您的變數位於開頭,那麼它顯然會被視為命令。

相關內容