Zsh 開發指南(第十六篇 alias 和 eval 的用法)

陌辭寒發表於2019-02-17

導讀

alias(別名)在 shell 中是非常常用的,它主要用於給命令起別名,簡化輸入。但主要用於互動場景,在指令碼中基本用不到。eval 是一個非常強大的命令,它的功能是將字串解析成程式碼再執行,但也會額外增加很多複雜性,非必要場景儘量少用。alias 和 eval 看起來好像沒什麼關係,但功能上有相似之處,所以放在一起講。

alias

最典型的例子是將 ls -l 簡化成 ll:

% alias ll=`ls -l`
% ll
total 0
drwx------ 0 goreliu goreliu 512 Aug 31 13:55 tmux-1000
drwxr-xr-x 0 goreliu goreliu 512 Aug 31 13:37 yaourt-tmp-goreliu複製程式碼

alias 的效果相當於直接將字串替換過來,比較好理解。

# 直接執行 alias,會列出所有的 alias
% alias
ll=`ls -l`
lla=`ls -F --color --time-style=long-iso -lA`
...複製程式碼

這樣的 alias 只有在行首出現時,才會被解析。但 zsh 中還有一種功能更強大的全域性 alias,不在行首也能被解析:

% alias -g G=`| grep`

% ls G tmux
tmux-1000複製程式碼

但這樣需要格外注意可能導致的副作用,比如我想建立一個名為 G 的檔案:

% touch G
touch: missing file operand
Try `touch --help` for more information.
Usage: grep [OPTION]... PATTERN [FILE]...
Try `grep --help` for more information.複製程式碼

結果 G 被替換了,只能在 G 兩邊加引號。

如果全域性 alias 沒用好,可能導致災難性的後果,比如誤刪重要檔案(像把某個全域性 alias 傳給 rm 後,恰好刪除了 alias 字串中的某些檔案),所以需要執行權衡後再使用,並且用的時候要多加註意。

eval

eval 的功能是將字串作為程式碼來執行。看上去好像很簡單,但實際涉及很複雜的內容,主要是符號轉義導致的語義問題。

在 bash 中,eval 的一個重要的使用場景是將變數的值當變數名,然後取它的變數值,類似於 c 語言中指向變數的指標:

% str1=str2
% str2=abc
% eval echo $$str1
abc複製程式碼

注意這裡有一個 和兩個 $,原因是第二個 $ 是和平時一樣,正常取 str1 的值的,而第一個 $ 需要轉義,因為它要在 eval 執行的過程中取 str2 的值,不能現在就展開。

這個用法很容易出問題,而且可讀性很差。幸好 zsh 中無需這麼用,有更好的辦法:

% str1=str2
% str2=abc
% echo ${(P)str1}
abc複製程式碼

(P) 專門用於這種場景,不需要再去轉義 $。

此外 eval 有時也用來動態執行程式碼,比如一個指令碼接受使用者的輸入,而這輸入也是一段指令碼程式碼,就可以用 eval 來執行它。但這種用法是極其危險的,因為指令碼中可能有各種危險操作,而且 shell 的語法很靈活,很難通過靜態掃描的方法判斷是否有危險操作。不可靠的程式碼根本不應該去執行。即使一定要執行,也可以先寫到檔案裡再執行,避免傳過來的程式碼影響到自身的邏輯。

但也不是說 zsh 中就完全沒有必要用 eval 了,在某些特別的場景(比如用於改造語法加語法糖)還是有用的。但如果要使用,就一定要注意它可能導致的副作用,利弊只能自己權衡了。eval 的具體用法,和 bash 中的基本沒有區別,可以去網上搜尋 bash eval 用法來了解,這裡就不介紹了。

總結

本文簡單介紹了 alias 的用法和 eval 的場景使用場景。alias 很簡單,主要在 .zshrc 裡使用。eval 很複雜,非必要場景儘量避免使用。

全系列文章地址:github.com/goreliu/zsh…

付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活定價,歡迎諮詢,微信 ly50247。

相關文章