我希望 shell 能夠警告我可能會犯的錯誤。
如何防止命令cmd2
在cmd1
.
例如:
$ tar tf file.tar
$ rm !$
在這裡,我只是忘記了列出該文件而不是提取其內容。
我正在尋找一個通用的解決方案,它根據前一個命令的名稱和返回值以及當前命令進行選擇。
答案1
在 bash 中,您可以設定shopt -s histverify
哪一項將阻止歷史記錄被一步展開和執行。這裡,第一次按 時,上面的內容$ rm !$
將擴展為,允許您在再次按執行之前進行檢查或編輯。$ rm file.tar
EnterEnter
更通用的解決方案將轉向“做我的意思”領土,需要一個程序來事後猜測你的意圖。
答案2
您要求很多通用答案,但在某種程度上應該可以相對容易地做到這一點。
然而,bash
至少有兩種通用機制可以幫助解決這個問題。您可以設定變數 PROMPT_COMMAND,這將在您在提示符號中執行任何內容後執行:
$ PROMPT_COMMAND='echo BOFH says hi!'
BOFH says hi!
$ man man
BOFH says hi!
$
我們可以用它來保存最後輸入的命令,然後重新讀取它,這樣我們就可以將它存儲在內存中以供進一步使用(在這種情況下歷史擴展不起作用):
$ PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
$ wc < test.sh | grep .
5 11 63
wc < test.sh | grep .
現在是邏輯部分,這完全取決於你。讓我們使用非常簡單的邏輯來阻止問題中的範例。要記住的是,bash 函數仍然可以在那裡工作,因此您不必將所有內容塞到單行、單一變數中。
$ # define the logic check
$ checkSanity() { grep -q "tar *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
checkSanity() { grep -q "tar *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
$ # feed it the last command
$ PROMPT_COMMAND='history -a; last=$(tail -n1 ~/.bash_history); checkSanity "$last"'
$ # simple test
$ tar tf test.sh 2>/dev/null
be careful, don't delete this
$ tar xf test.sh 2>/dev/null
$
當然,這種方法對於防止 PEBKAC 很有用(特別是如果您sleep 3
在末尾添加),但它本身無法破壞下一個命令。
如果那是真的你想要什麼,捕獲DEBUG
信號(例如trap 'echo "I am not deterministic, haha"' DEBUG
),因為它預先運行。結合這兩種方法時要小心,因為輸出/操作將加倍:
$ df
/.../
$ trap 'tail -n1 ~/.bash_history' DEBUG
df
df
trap 'tail -n1 ~/.bash_history' DEBUG
trap 'tail -n1 ~/.bash_history' DEBUG
若要讓陷阱中斷指令,您必須啟用extdebug
( shopt -s extdebug
)。您也不需要不斷保存和重新讀取歷史記錄,但可以檢查$BASH_COMMAND
以獲取即將運行的命令。然後,您只需要確保邏輯檢查器在偵測到不良情況時傳回 1,否則傳回 0。
extdebug
If set, behavior intended for use by debuggers is enabled:
/.../
2. If the command run by the DEBUG trap returns a non-zero value, the next
command is skipped and not executed.
$ checkSanity() { if grep -q "tar *[tf][[:alpha:]]*[tf] " <<< "$1"; then echo "be careful, don't delete this"; return 1; fi; }
$ trap 'checkSanity "$BASH_COMMAND"' DEBUG
$ # simple test
$ tar tf test.sh 2>/dev/null
be careful, don't delete this
$ tar xf test.sh 2>/dev/null
$
答案3
在這種情況下,您將從命令的錯誤警告中受益rm
。
在 shell 初始化腳本中(假設bash
, so ~/.bashrc
),您可以rm
使用-i
或 的別名-I
。
alias rm="rm -i"
從man 1 rm
-i prompt before every removal
-I prompt once before removing more than three files, or when
removing recursively. Less intrusive than -i, while still
giving protection against most mistakes
更普遍的問題是“我如何保護我的系統免受我自己的侵害”之前討論過。簡而言之,注意你在做什麼,並且僅在root
必要時運行命令。
答案4
根據您的具體情況,我會這樣做:
tar tf file.tar
if [ -f file ]; then # Assuming you meant to extract a file
rm -f file.tar
else
echo "file is missing. Command failed."
fi
如果您想檢查錯誤並僅在第一個命令成功時執行下一個命令
some_command && another_command
儘管在您的特定情況下,第二個命令仍然會運行,因為它沒有錯誤,即使它沒有執行您想要的操作。