Bash 和 Zsh 是否有一種模式可以在按 Enter 鍵時回顯別名擴充的內容?

Bash 和 Zsh 是否有一種模式可以在按 Enter 鍵時回顯別名擴充的內容?

例如,如果我有一個

alias dbmigrate='rails db:migrate'

是否有一種模式或簡單的方法可以在 Bash 和 Zsh 中進行配置,以便當我在 shell 中鍵入時:

$ dbmigrate  # press Enter

它會在運行之前回顯別名擴展為什麼?

答案1

巴什,有alias-expand-linehistory-and-alias-expand-linereadline 函數,但預設情況下它們不會綁定到任何鍵。您可以自己綁定它們 - 例如Control-T

bind '"\C-T": history-and-alias-expand-line'

嘗試綁定Enter自身會很混亂,因為並非任何時候您按下Enter都會執行命令(例如,當它是不完整的管道時,等等)。

還有一個DEBUG陷阱,但是確定該命令是否實際上是由用戶輸入的(例如,不是PROMPT_COMMAND從中命令替換啟動的PS1),以及它是否是別名擴展的,這將是很棘手的;但如果你同意列印任何執行前的命令:

trap 'echo "> $BASH_COMMAND"' DEBUG

bash$ pwd
> pwd

桀騁,您可以簡單地定義preexec函數,如果與使用者輸入的命令不同,則列印擴充命令:

preexec(){ [ $1 != $2 ] && print -r "> $2" }

zsh$ j
> jobs

但請注意,如果強制擴展別名,某些別名+歷史記錄技巧將無法正常運作。例如,我c在 bash 中有一個別名來執行諸如 之類的計算c 3.17 * 4.2,而不必轉義*,(等:

alias c='_c=$(fc -nl -0); bc -l <<<${_c#*c} #'

一旦 readline 展開它,歷史記錄中的當前行(由 返回的行fc -nl -0)將是擴大,不是原來的命令,一切都會崩潰。

答案2

別名只是簡單的替換。如果您想做一些更奇特的事情,例如在運行命令之前列印一條訊息,您需要更強大的東西:函數。如果您希望定義看起來像別名定義,則可以定義定義函數的函數。

function verbose_alias {
  local name=${1%%=*} expansion=${1#*=}
  eval "function $name {
    printf >&2 '%s is an alias for %s\\n' \"$name\" \"$expansion\";
    $expansion \"\$@\";
  }"
}
verbose_alias dbmigrate='rails db:migrate'

答案3

POSIX 需求set命令有這個選項

-x

   shell 應在擴展命令之後和執行命令之前向標準錯誤寫入每個命令的追蹤。未指定是否追蹤關閉追蹤的命令。

https://pubs.opengroup.org/onlinepubs/009604499/utilities/set.html

因此您可以在任何相容的 shell 上使用set -x或。set -o xtrace在 bash 中,您可以在手冊頁中看到這一點:

-x

   展開每個簡單指令、for 指令、case 指令、select 指令或算術 for 指令後,顯示 PS4 的展開值,後面接著該指令及其展開參數或關聯的單字清單。

xtrace

   與...一樣-x

https://linux.die.net/man/1/bash

zsh 也有類似的選項set內建

XTRACE-x,克什-x:)

   執行命令時列印命令及其參數。

https://linux.die.net/man/1/zshoptions

您也可以-x在執行腳本或命令時指定選項

bash -x -c "echo This will be printed before running; ll"
bash -x script-to-be-debugged.sh
zsh -x -c "...; 3; md did-you-see-the-aliases"
zsh -x buggy-script.sh

請注意,它還擴展了每個提示之前和之後運行的命令,因此在許多情況下可能並不理想,例如當您git在 PS1 中使用變數時。在我乾淨的 Ubuntu VM 中,僅列印出正在執行的命令

也可以看看有什麼set -x作用?

另一個選項是set -vorset -o verbose在列印之前不擴展變數

答案4

bash 預設情況下不提供這種幫助。

預設情況下可用的兩個相關函數是:

  • shopt -s histverify

如果設定並且正在使用 readline,則歷史取代的結果不會立即傳遞到 shell 解析器。相反,生成的行將加載到讀取行編輯緩衝區中,從而允許進一步修改。

它解決了按下時的操作部分Enter,但僅在命令列上具有歷史擴展。例如:

$ shopt -s histverify
$ echo "this is a test"
This is a test
$ echo !!
$ echo echo "this is a test"  <---- expanded by the simple use of enter!! 
  • 閱讀線shell-expand-line

外殼擴展線 (MCe)

像 shell 一樣展開該行。這將執行別名和歷史擴展以及所有 shell 字擴展。有關歷史擴展的描述,請參閱下面的歷史擴展。

這正是您要求完成的,但使其發揮作用的關鍵是Ctrl- Alt-e

shell-expand-line抱歉,我不知道適用於 Enter 和executes 的解決方案。

相關內容