Bash

bash - 為什麼 type -a 執行 ‘$(printf ‘a’)’ 並且是否有可能取回原始別名?

  • May 11, 2015

兩天前我問了這個問題後,我決定在我的 ~/.bashrc 中創建這個別名:

別名 catvu=“LC_ALL=C sed "$(printf ’s/

$$ ^\t -\176\200-\377 $$/^&/g’)"|LC_ALL=C tr ‘\0-\10\13-\37\177’ ‘@-HK-_?’”

如果我通過 grep 查詢別名,則輸出是正確的:

[xiaobai@xiaobai note]$ grep catvu ~/.bashrc
alias catvu="LC_ALL=C sed \"$(printf 's/[^\t -\176\200-\377]/^&/g')\"|LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?'"

但是 printf 消失的輸出略有不同:

[xiaobai@xiaobai note]$ type -a catvu
catvu is aliased to `LC_ALL=C sed "s/[^  -~�-�]/^&/g"|LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?''

我嘗試使用cat -v

[xiaobai@xiaobai note]$ type -a catvu | cat -v
catvu is aliased to `LC_ALL=C sed "s/[^  -~M-^@-M-^?]/^&/g"|LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?''

hexdump -C

[xiaobai@xiaobai note]$ type -a catvu | hexdump -C                                                                                                    
00000000  63 61 74 76 75 20 69 73  20 61 6c 69 61 73 65 64  |catvu is aliased|                                                                        
00000010  20 74 6f 20 60 4c 43 5f  41 4c 4c 3d 43 20 73 65  | to `LC_ALL=C se|                                                                        
00000020  64 20 22 73 2f 5b 5e 09  20 2d 7e 80 2d ff 5d 2f  |d "s/[^. -~.-.]/|                                                                        
00000030  5e 26 2f 67 22 7c 4c 43  5f 41 4c 4c 3d 43 20 74  |^&/g"|LC_ALL=C t|                                                                        
00000040  72 20 27 5c 30 2d 5c 31  30 5c 31 33 2d 5c 33 37  |r '\0-\10\13-\37|                                                                        
00000050  5c 31 37 37 27 20 27 40  2d 48 4b 2d 5f 3f 27 27  |\177' '@-HK-_?''|                                                                        
00000060  0a                                                |.|                                                                                       
00000061                                                                                                                                              
[xiaobai@xiaobai note]$ 

我縮小範圍:

alias catvu2="$(printf 'a')"

輸出變為:

[xiaobai@xiaobai note]$ type -a catvu2
catvu2 is aliased to `a'
[xiaobai@xiaobai note]$ 

哪個命令相同:

[xiaobai@xiaobai note]$ which catvu2
alias catvu2='a'
[xiaobai@xiaobai note]$ 

所以我的問題是為什麼要執行**$(printf以及如何使用type -a命令獲取原始原始字元串?**

嘗試以下兩個命令,看看你得到了什麼:

echo "$(printf 'a')"
echo '$(printf 'a')'

本質上,單引號將為您提供“原始原始字元串”,而雙引號中的任何內容都將在分配給您的別名之前進行評估。

但是,您可能會注意到第二個命令的輸出中缺少 ‘a’ 周圍的單引號。您必須仔細檢查並跟踪您的引號以避免失去引號 - 就像您必須使用\"內部雙引號一樣,除非您不能在單引號內這樣做。你必須使用類似的東西'\''

出於這個原因,我建議使用函式而不是別名,這樣您就不必擔心保護引號。這也將允許您在命令行上提供文件名,而您的別名僅在您將某些內容輸入其中時才有效。

catvu () {
   LC_ALL=C sed "$(printf 's/[^\t -\176\200-\377]/^&/g')" "$@" | LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?'
}

請注意,命令替換$(printf ....)在雙引號內:

alias catvu="LC_ALL=C sed \"$(printf 's/[^\t -\176\200-\377]/^&/g')\"|LC_ALL=C tr '\0-\10\13-\37\177' '@-HK-_?'"

因此,在定義別名之前$(printf ....)執行命令替換。

讓我們舉一個更簡單的例子來說明同一點。讓我們定義一個 shell 變數d

$ d="a b $(printf "%s" hello) c d"

現在,讓我們declare -p來看看究竟是如何d定義的:

$ declare -p d
declare -- d="a b hello c d"

同樣,就像別名一樣,在定義 shell 變數之前首先執行命令替換。

延遲執行printf

考慮:

$ alias abc='echo a b $(printf "%s" Hello) c d'

在上面,$(printf ...)是在單引號內。因此,不會執行命令替換,並且該printf語句是別名定義的一部分:

$ alias abc
alias abc='echo a b $(printf "%s" Hello) c d'

printf然而,當我們執行別名時執行:

$ abc
a b Hello c d

引用自:https://unix.stackexchange.com/questions/202638