解決 Cygwin 環境下執行 bash 出現錯誤「$'\r': command not found」

在 Windows 上執行 Bash Script 時,遇到「$'\r': command not found」錯誤,問題倒不是因為程式語法錯誤,而是跨作業系統開發時會遇到的換行符號差異。只要將 Windows 的 CRLF 換行格式轉換為 Unix/Linux 使用的 LF,就可以解決。

Photo by Christina Morillo on StockSnap
 

錯誤狀況

Cygwin 環境下執行 bash 出現錯誤「$'\r': command not found」

$ bash example.sh

example.sh: line 3: $'\r': command not found

: invalid option name set: pipefail

example.sh: line 5: $'\r': command not found

example.sh: line 8: $'\r': command not found

example.sh: line 9: syntax error near unexpected token `$'{\r''

解決方法

1. 下載與安裝 Cygwin 安裝程式

2. 執行 Cygwin,開啟視窗介面,確認是否已經安裝 dos2unix 套件,輸入指令:

$ which dos2unix

3. 如果 dos2unix 不存在,需要安裝 dos2unix 套件。離開 Cygwin 視窗,在 Windows 命令列提示字元執行:

setup-x86_64.exe -q -P dos2unix

參數說明

  • setup-x86_64.exe:Cygwin 64 位元安裝程式。
  • -q:安靜模式(quiet mode),不顯示一般安裝介面。
  • -P dos2unix:指定要安裝的套件名稱為 dos2unix。

也可以透過 Cygwin 視窗介面安裝,請參考連結

4. 執行 Cygwin,開啟視窗介面

5. Cygwin 環境下執行 cd 指令,切換到 bash 檔案所在的資料夾

$ cd c:\path\to\folder

$ cd /cygdrive/c/path/to/folder

6. Cygwin 環境下執行 dos2unix 指令,將 bash 檔案的換行符號,從 Windows 的 CRLF 換行 (\r\n) 格式,轉換成 Unix/Linux 的 LF 換行格式 (\n)。

$ dos2unix example.sh

或者一次轉換目前目錄下的多個 bash 檔案

$ dos2unix *.sh

7. 再次執行 bash 檔案,就不會遇到相同錯誤

$ bash example.sh

如果不使用 dos2unix,網路上提供使用 sed 程式轉換換行符號的指令,將指定檔案中的 \r 移除,可自行嘗試

sed -i 's/\r$//' example.sh

探討問題原因

bash 檔案是透過 GIT 從 macOS 同步 (clone 或 pull) 到 Windows Server。雖然 macOS 文字檔案預設換行符號是 \n,但是因為 Windows Server 的 GIT 設定了自動轉換換行符號是 \r\n,而造成錯誤。

1. 檢查 GIT 設定,在 Windows 命令列提示字元執行:

git config --get core.autocrlf

回傳結果 true。

設定 core.autocrlf=true ,Git 在 Windows 工作目錄簽出 (check out) 檔案時會將 LF 轉換成 CRLF;在提交 (commit) 時則會把 CRLF 正規化為 LF。此設定可能會被 .gitattributes 中的換行規則覆蓋。(資料來源:git-scm.com)

2. 使用 .gitattributes 強制規範換行符號

在 GIT 專案的根目錄位置,新增檔案 .gitattributes

*.sh text eol=lf

3. 將 GIT 專案套用新的 .gitattributes 規則

git add .gitattributes
git add --renormalize .
git status # 確認哪些檔案被重新正規化
git commit -m "Normalize line endings for shell scripts"
git push

參數說明

  • git add:把變更加入暫存區。
  • --renormalize:重新讀取已追蹤檔案 Tracked files,並依目前的 .gitattributes 設定,重新套用換行正規化及其他加入 Git 暫存區前的內容轉換規則 (Git clean filter)。
  • .:處理目前目錄及所有子目錄

4. Windows 透過 git 同步正規化設定

git pull


參考資料

  1. Cygwin - 維基百科,自由的百科全書 https://zh.wikipedia.org/zh-tw/Cygwin 「Cygwin是許多自由軟體的集合,最初由Cygnus Solutions開發,用於各種版本的Microsoft Windows上,執行類UNIX系統。」
  2. windows - Cygwin Dos2Unix Command not found - Super User https://superuser.com/questions/612435/cygwin-dos2unix-command-not-found
  3. dos2unix 指令在 Cygwin 裡面找不到。在其他電腦上安裝的 Cygwin 都可以用,所以不知道為什麼... : r/linux4noobs https://www.reddit.com/r/linux4noobs/comments/95pnrb/dos2unix_command_not_found_on_cygwin_worked_fine/
  4. Git - git-config Documentation https://git-scm.com/docs/git-config
  5. Configuring Git to handle line endings - GitHub Docs https://docs.github.com/en/get-started/git-basics/configuring-git-to-handle-line-endings
  6. 跨平台開發--換行符號. 多人協作開發時,難免會遇到不同作業系統,一般情況下不同系統並不會影響開發,但在某… | by Jimmy | Medium https://medium.com/@okesseko/%E8%B7%A8%E5%B9%B3%E5%8F%B0%E9%96%8B%E7%99%BC-%E6%8F%9B%E8%A1%8C%E7%AC%A6%E8%99%9F-a313d96346c8
  7. Git 在 Windows 平台處理斷行字元 (CRLF) 的注意事項 | The Will Will Web https://blog.miniasp.com/post/2013/09/15/Git-for-Windows-Line-Ending-Conversion-Notes


留言