為什麼這個微不足道的 rm -rf 命令會破壞我的作業系統?
我使用 Bash 4.3.48(1) 並在測試 VPS 機器上執行以下命令模式:
rm -rf ${drt}/${pma}*
該命令刪除了整個作業系統(Ubuntu)。執行
cd /
which 只返回以下錯誤,這一點很明顯:bash: cd /: 沒有這樣的文件或目錄
深入研究,這是因為上面原始命令中的兩個變數都沒有聲明:
- 我創建了一個名為的文件
~/repoName/assignments_variables.sh
,其中包含導出變數的列表(包括drt
和pma
)。- 而不是 running
source /etc/bash.bashrc
, I ran/etc/bash.bashrc
,這是錯誤的,因為該文件僅與目前會話相關(儘管它可用於隨後執行文件,這些文件本身在子會話中執行數據)。現在我很清楚錯誤的路徑是問題的一般原因,我想深入一點,問這個問題:
為什麼
rm -rf
忽略了錯誤的變數擴展並繼續前進/*
?我知道只有在找到目錄時才rm -rf
應該刪除它,因此不應該依賴不存在的目錄的部分路徑(比如導致作業系統刪除)。我如何改進命令以涵蓋將來可能出現的類似錯誤路徑(由於錯誤的變數擴展)情況?/*``rm -rf
是否有一些 Bash 指令來確保 Bash 永遠不會擴展空變數(直到我撤消該指令)?
讓我強調一下:我通常不僅使用備份,還使用雙重備份。那確實是一個在後台有 x3 備份的測試環境。
正如已經指出的那樣,這兩個變數
drt
並pma
沒有出現在您的腳本環境中,這意味著 shell 將這些變數擴展為空字元串。結果命令是rm -rf /*
(*
進一步擴展到根目錄中可用的任何內容)。以 root 身份執行不會刪除根目錄本身
rm -rf /*
。另外,我(和向我指出的Jesse_b )對錯誤消息感到有些困惑bash: cd /: No such file or directory
我自己能夠引發此錯誤消息的唯一方法是執行命令
"cd /"
(注意引號)。真的/
被刪除了,錯誤資訊會說bash: cd: /: No such file or directory
艾薩克已經給出了一些關於如何防止你在未來做這樣的事情的提示,但我認為我只是提出我的建議。
不要在root shell 提示符下工作。
如果編寫需要 root 權限
sudo
的腳本,請在腳本中使用實際需要這些提升權限的*特定命令。*不要以 root 身份執行整個腳本,尤其是在開發期間。您通常不需要
/etc/bash.bashrc
出於任何原因觸摸,並且您永遠不必明確來源它。環境變數可以在
- 使用者自己的
$HOME/.bashrc
(如果腳本要從互動式會話中執行),或者- 在腳本本身中,或
- 在由腳本明確提供的單獨文件(為腳本編寫)中,或
BASH_ENV
在環境變數指向的文件中。在這種情況下可以拯救您的另一個安全措施是在 ( ) 下執行您的腳本,也可能在( )
set -u
下執行。shell 選項將威脅擴展未設置的變數作為錯誤,而如果命令以非零退出狀態退出,則 shell 選項將立即退出 shell 會話。nounset``set -e``errexit``nounset``errexit
劇本
#!/bin/bash -ue echo "$hello" echo "world"
永遠不會輸出
world
,而是會引發消息script.sh: line 3: hello: unbound variable
在終止之前。(在這個簡單的例子中
-u
,它是終止的,-e
它不做任何事情)。
如果變數不存在,擴展什麼?
讓我們試試(注意迴聲):
$ unset drt pma $ echo rm -rf ${drt}/${pma}* rm -rf /bin /boot /dev /etc /hello /home /initrd.img /lib /lib32 /lib64 /libx32 /media /mnt /opt /proc /root /run /sbin /srv /sys /tmp /usr /var /vmlinuz /vmlinuz.old
那是整個系統(正如您已經確認的那樣)。
問題是外殼完成的擴展。
預防
我們如何防止這種情況發生?
通過防止外殼擴展空變數。如果 var 為空或未設置,則產量
的擴展。並停止執行(嚴重錯誤)。測試它:
${var:?message}``message
$ echo rm -rf "${drt:?Missing variable drt}"/"${pma:?Missing variable pma}"*
該解決方案與 POSIX 兼容。