$PROMPT_COMMAND 是冒號分隔的列表嗎?
我想
.bash_history
通過設置PROMPT_COMMAND
在所有終端選項卡和視窗中啟用我的命令歷史記錄.profile
:export PROMPT_COMMAND="history -a; history -c; history -r;$PROMPT_COMMAND"
但是,當我檢查此環境變數是否已設置時,我得到:
echo $PROMPT_COMMAND printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"
像這樣導出會
PROMPT_COMMAND
覆蓋我現有的$PROMPT_COMMAND
列表,還是有必要在導出之前PROMPT_COMMAND
用 a作為前綴?:
作為 google 搜尋時的最佳結果之一
"PROMPT_COMMAND seperator"
,我覺得答案值得比迄今為止給出的更多努力。**注意:**在準備這篇文章時,我測試了 Bash 版本 3.2、4.4、5.0 和 5.1(通過docker)並查看了相同版本的原始碼(通過gnu.org)
讓我們開始 …
Bash 手冊
重擊 <= v5.0
變數 PROMPT_COMMAND 的值在之前檢查 Bash 列印每個主要提示。如果設置了 PROMPT_COMMAND 並且 有一個非空值,那麼這個值就像它一樣被執行 已在命令行中鍵入。
這是什麼意思?
這意味著 bash 一般相當於:
eval "${PROMPT_COMMAND:-}"
因此,任何適用於此的命令連結/排序
eval
都是允許的。重擊 >= v5.1
Bash 檢查數組變數 PROMPT_COMMAND 的值 就在列印每個主要提示之前。 如果 PROMPT_COMMAND 中的任何元素已設置且非空,則 Bash 按數字順序執行每個值,就好像它已經 在命令行中鍵入。 ... 如果設置了這個變數,並且是一個數組,那麼每個變數的值 set 元素被解釋為要執行的命令 在列印主要提示 ($PS1) 之前。 如果設置了但不是數組變數,則使用其值 作為要執行的命令。
這是什麼意思?
這意味著 bash 一般相當於:
if [[ ${#PROMPT_COMMAND[@]} -gt 1 ]]; then for cmd in "${PROMPT_COMMAND[@]}"; do eval "${cmd:-}"; done else eval "${PROMPT_COMMAND:-}" fi
即數組的每個元素都是
eval
獨立的社區在做什麼
在github上搜尋
"PROMPT_COMMAND"
顯示:
- 總的來說,社區
;
用作分隔符- 某些事件
$'\n'
用作分隔符我具體看到的
作為軼事說明:
- Mac OSX 使用
;
(參見/etc/bashrc_Apple_Terminal
)- Bash-PreExec 似乎使用
$'\n'
- Bash-It使用
;
讓我們看看他們的行動
首先,讓我們獲得一個全新的 Bash v3.2 環境:
docker run -it --rm bash:3.2 bash-3.2$
分號分隔的字元串
使用
;
-delimited 字元串進行測試會產生:bash-3.2$ PROMPT_COMMAND='printf 1;printf 2;printf 3;printf ":\n"' 123: bash-3.2$
行分隔的字元串
\n
使用-delimited 字元串對此進行測試會產生:bash-3.2$ PROMPT_COMMAND=$'printf 1\nprintf 2\nprintf 3\nprintf ":\n"' 123: bash-3.2$
混合兩者
我們可以混合使用兩種分隔符嗎?呸!:
bash-3.2$ PROMPT_COMMAND=$'printf 1;printf 2\nprintf 3;printf ":\n"' 123: bash-3.2$
陣列怎麼樣?
我們要去哪裡,我們需要 Bash v5.1
docker run -it --rm bash:5.1 bash-5.1$
文字數組
使用文字數組對此進行測試會產生:
bash-5.1$ PROMPT_COMMAND=( "printf 1" "printf 2" "printf 3" "printf ':\n'" ) 123: bash-5.1$
使用所有三個!
如果你把它們都混合起來怎麼辦:
bash-5.1$ PROMPT_COMMAND=( "printf 1" $'printf 2\nprintf 3' 'printf 4;printf ":\n"' ) 1234: bash-5.1$
使用哪一個?
如果
${PROMP_COMMAND}
是一個數組,您應該將您的命令附加/前置到數組中。注意,如果您願意,您可以將命令組(即,單行
;
或$'\n'
分隔的命令字元串)作為單個條目附加到數組中。如果
${PROMP_COMMAND}
不是數組,那麼您可能應該在添加命令時使用;
,因為它感覺像是一個更正式的分隔符,但知道您添加的命令可以是更複雜的腳本,這些腳本本身可以包含分隔的步驟由$'\n
’。我會嘗試使用 munging 功能嗎?
當然 !
## # pc_munge munges PROMPT_COMMAND. # Tries to accommodate when PROMPT_COMMAND is an array (supported in Bash v5.1+). # If ${#PROMPT_COMMAND[@]} has 2+ elements, then we treat as an array, otherwise # we defensively treat it as a string. # By default, uses ';' as separator. # # NOTE: Does NOT check if command is already present # # Parms: # $1 command to add # $2 before | after (default: after) # $3 separator (default: ';') # pc_munge() { [[ -n "$1" ]] || return local fs="${3:-;}" # null | '' => default case "${2:-after}" in before) [[ ${#PROMPT_COMMAND[@]} -gt 1 ]] && PROMPT_COMMAND=( "$1" "${PROMPT_COMMAND[@]}" ) || PROMPT_COMMAND="${1}${PROMPT_COMMAND:+${fs}$PROMPT_COMMAND}" ;; *) # after [[ ${#PROMPT_COMMAND[@]} -gt 1 ]] && PROMPT_COMMAND+=( "$1" ) || PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND${fs}}${1}" ;; esac }
bash
$PROMPT_COMMAND
(或者每個元素,如果它是一個帶有 bash 5.1+ 的數組,正如@DavidFarrell 已經指出的那樣)被解釋為 shell 程式碼,所以你可以像編寫 shell 腳本一樣編寫它的內容。在 shell 腳本中,命令可以用;
,newline
,|
,&
,&&
,||
等分隔,每個命令都有自己的含義。所以你可以有例如:
PROMPT_COMMAND=' cmd1 && cmd2 & cmd3; cmd4 for cmd in cmd5 cmd6; do "$cmd" done cmd7 << "EOF" foo bar EOF'
等等
要將命令附加到已設置的命令
$PROMPT_COMMAND
並確保它獨立於之前的命令執行,您可以選擇;
和newline,但如果最初為空或在此處以文件分隔符結尾的特殊情況下;
將不起作用$PROMPT_COMMAND
(就像我們EOF
上面的),這樣做:PROMPT_COMMAND+=' your extra command here'
(或舊版本:
PROMPT_COMMAND=$PROMPT_COMMAND' your extra command here'
)
更可取。或者:
PROMPT_COMMAND='your extra command here '$PROMPT_COMMAND
預先添加它,以便它首先執行。
使用 bash 5.1+,您還可以附加一個數組元素:
PROMPT_COMMAND+=( 'your extra command here' )
或前置:
PROMPT_COMMAND=( 'your extra command here' "${PROMPT_COMMAND[@]}" )
這留下了一個潛在的問題:如果啟用了
errexit
(-e
) 選項,並且這些腳本中的任何命令都失敗了,則處理會在那裡停止¹,因此您的額外命令可能最終不會執行。不過,這可能應該被視為一個病態的案例。errexit
在互動式 shell 中使用可能是個壞主意(在腳本中使用時已經頗有爭議)。為了比較,在 中
zsh
,而不是在 中$PROMPT_COMMAND
,您有在不同點呼叫的鉤子函式,其靈感來自(並改進了)中類似命名的特殊別名。是您要定義的函式,以便在每個提示之前呼叫它。在中,您也可以改為使用要呼叫的額外函式來設置特殊數組(也會影響那裡的處理¹)。tcsh``precmd()``zsh``precmd_functions``errexit
¹ 選項也可能發生同樣的情況,
nounset
或者在處理過程中遇到語法錯誤或任何類型的致命錯誤。