MSYS2などのLinuxでCRLF(キャリッジリターン)を使用してBashスクリプトを処理しますか?

MSYS2などのLinuxでCRLF(キャリッジリターン)を使用してBashスクリプトを処理しますか?

次の簡単なスクリプトがあるとしますtmp.sh

echo "testing"
stat .
echo "testing again"

それは単純ですが\r\n(つまり、CRLF、つまりキャリッジリターン+ラインフィード)で終わります。 Webページは行末を保持しないため、以下は16進ダンプです。

$ hexdump -C tmp.sh 
00000000  65 63 68 6f 20 22 74 65  73 74 69 6e 67 22 0d 0a  |echo "testing"..|
00000010  73 74 61 74 20 2e 0d 0a  65 63 68 6f 20 22 74 65  |stat ...echo "te|
00000020  73 74 69 6e 67 20 61 67  61 69 6e 22 0d 0a        |sting again"..|
0000002e

これで、スクリプトはWindowsのMSYS2で起動および開発されたため、CRLF行の終わりがあります。したがって、Windows 10のMSYS2で実行すると、予想される結果が得られます。

$ bash tmp.sh
testing
  File: .
  Size: 0               Blocks: 40         IO Block: 65536  directory
Device: 8e8b98b6h/2391513270d   Inode: 281474976761067  Links: 1
Access: (0755/drwxr-xr-x)  Uid: (197609/      USER)   Gid: (197121/    None)
Access: 2020-04-03 10:42:53.210292000 +0200
Modify: 2020-04-03 10:42:53.210292000 +0200
Change: 2020-04-03 10:42:53.210292000 +0200
 Birth: 2019-02-07 13:22:11.496069300 +0100
testing again

ただし、このスクリプトをUbuntu 18.04システムにコピーして実行すると、他の結果が表示されます。

$ bash tmp.sh
testing
stat: cannot stat '.'$'\r': No such file or directory
testing again

同じ行末を持つ他のスクリプトのUbuntu bashでもこのエラーが発生しました。

line 6: $'\r': command not found

…おそらく空の行から来たのでしょう。

そのため、Ubuntuの何かがEnterに停止したようです。私は見たBASHとキャリッジリターン動作:

Bashとは何の関係もありません。 \r および \n は Bash ではなく端末で解釈されます。

...しかし、これはコマンドラインにそのまま入力された内容にのみ適用されるようです。\rそしてこれは\nすでにスクリプト自体に入力されているので、Bashはこれをここで解釈する必要があります\r

UbuntuのBashバージョンは次のとおりです。

$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

...MSYS2のBashバージョンは次のとおりです。

$ bash --version
GNU bash, version 4.4.23(2)-release (x86_64-pc-msys)

(それらの間のギャップはそれほど大きくないようです...)

\rとにかく私の質問は - Ubuntu / LinuxのBashを「印刷可能な文字」として解釈するのではなく、これを無視するように説得する方法はありますか?こう説明します)?編集する:いいえスクリプト自体を変換する必要があります(たとえば、gitでこの方法でチェックすると、CRLF行の末尾に変更されていません)。

EDIT2:私は一緒に作業している他の人がWindowsのテキストエディタでスクリプトを再開し、\r\nスクリプトを再導入してコミットできるので、この方法を好みます。これにより、無限のコミットストリームが発生する可能性があります。リザーバーを汚染する\r\n変換です\n

編集2:@ Kusalanandaがコメントでdos2unix()を言及しましたsudo apt install dos2unix。次のように書いてください。

$ dos2unix tmp.sh 
dos2unix: converting file tmp.sh to Unix format...

...ファイルを内部で変換してstdoutに出力します。 stdinリダイレクトを設定する必要があります。

$ dos2unix <tmp.sh | hexdump -C
00000000  65 63 68 6f 20 22 74 65  73 74 69 6e 67 22 0a 73  |echo "testing".s|
00000010  74 61 74 20 2e 0a 65 63  68 6f 20 22 74 65 73 74  |tat ..echo "test|
00000020  69 6e 67 20 61 67 61 69  6e 22 0a                 |ing again".|
0000002b

...その後、原則としてUbuntuで実行できます。この場合はうまくいくようです。

$ dos2unix <tmp.sh | bash
testing
  File: .
  Size: 20480       Blocks: 40         IO Block: 4096   directory
Device: 816h/2070d  Inode: 1572865     Links: 27
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2020-04-03 11:11:00.309160050 +0200
Modify: 2020-04-03 11:10:58.349139481 +0200
Change: 2020-04-03 11:10:58.349139481 +0200
 Birth: -
testing again

しかし、覚えておくべき少し混乱したコマンドに加えて、stdinはもはや端末ではないので、bashの意味も変わります。この簡単な例では動作します。https://stackoverflow.com/questions/23257247/pipe-a-script-into-bashより大きな質問のような。

ベストアンサー1

私が知っている限り、BashにWindowsスタイルの行末を許可するように指示する方法はありません。

Windowsが関連している場合は、autocrlf設定フラグを使用してコミット時に行末を自動的に変換するGitの機能に依存するのが一般的な方法です。例を見る行末のGitHubドキュメント、これはGitHubに限定されません。このようにして、ファイルはリポジトリからUnixスタイルの行末にコミットされ、各クライアントプラットフォームに合わせて変換されます。

(その逆は問題ではありません。MSYS2はWindowsでUnixスタイルの行末をうまく処理します。)

おすすめ記事