shell腳本沒有將空格作為參數分隔符(有人可以解釋一下那個小文件的區別嗎?)
短版(TL;DR)
我有 2 個小的單行文件,看似相同:
$ cat f1 f2 ./cconv.sh 100 EUR USD ./cconv.sh 100 EUR USD
但它們不是,大小有 1 個字節的差異:
$ ls -l f1 f2 (...) 24 oct. 30 16:19 f1 (...) 23 oct. 30 16:19 f2 $ diff f1 f2 1c1 < ./cconv.sh 100 EUR USD --- > ./cconv.sh 100 EUR USD
我曾經
dhex
計算出十六進制的差異。看起來 :
f1
完成c2 a0 55 53 44 0a
f2
完成20 55 53 44 0a
有人知道這裡發生了什麼嗎?有什麼區別,更重要的是,它來自哪裡?這是包含 2 個文件的 zip 文件的連結,以及
dhex
結果的螢幕截圖。長版(附加說明)
這 2 個文件摘自我的
~/.bash_history file
.我注意到我的貝殼有一種非常奇怪的行為。採用以下非常基本的腳本:
#!/bin/sh echo $# echo "$1" echo "$2" echo "$3" exit 0
在某些情況下(但哪些 ???),它不會將空格作為參數分隔符:
$ ./cconv.sh 100 EUR USD 2 100 EUR USD
但有時它會按預期工作:
$ ./cconv.sh 100 EUR USD 3 100 EUR USD
它讓我發瘋!我花了幾個小時試圖弄清楚發生了什麼。以下是我為縮小範圍所做的一些測試:
我在一台裝有 Debian 11、Gnome 3.38 的筆記型電腦上工作。但我碰巧也有一台作業系統完全相同的虛擬機(D11,G3.38),在虛擬機中一切正常。所以很明顯,我一定是對我的裸機筆記型電腦做了一些事情,讓它表現不佳。但是什麼???
我注意到這個問題只發生在圖形會話中。如果我打開一個 tty (Ctrl+Alt+F n ),它工作正常
我懷疑我的終端模擬器。但是在不同的模擬器中行為是相同的(我試過 Gnome Terminal、Terminator 和 Konsole,結果相同)
我懷疑是貝殼。但是 Bash 或 Dash 的行為是相同的
我禁用了我能想到的所有自定義:
- 我暫時刪除了
/etc/bashrc
,/etc/profile
,/etc/inputrc
和/etc/rc.local
- 我暫時刪除了
~/.bashrc
,~/.profile
並且~/.inputrc
- 我禁用了所有 Gnome Shell 的擴展
我什至懷疑是鍵盤,並插入了 USB 鍵盤。結果相同。
我真的很困惑,不知道發生了什麼。我終於注意到 2 個命令之間的細微差別
~/.bash_history
:一個來自我的 Gnome 會話,另一個來自我的 tty 會話。顯然存在差異,但究竟是什麼,可能是什麼原因?
c2 a0
是不間斷空格字元的 UTF-8 編碼。它通常看起來像一個正常空格,但不被 shell 辨識為空格。在一些鍵盤映射中,諸如 AltGr+Space 或 Option+Space 之類的東西會產生不間斷的空格。如果您的鍵盤映射在 AltGr 或 Option 後面也有例如豎線字元,這會很有趣,這樣可以更容易地鍵入
|<nbsp>
而不是|<sp>
,給您這樣的錯誤:$ echo foo | grep . bash: grep: command not found
(我認為 SE 會將 nbsp 折疊到正常空間,因此如果從此處複製粘貼,您可能不會收到錯誤消息。)
如果您從其他工具複製並粘貼參數,您可能會從那裡得到奇怪的格式,但這取決於程序。
有關不生成字元的一些解決方案,請參閱在 shell 中處理 nbsp字元。