入力ファイルの行がDOS(CR/LF)またはUnix(LF)改行で終わるかどうかを判断するシェルスクリプトを作成しようとしています。シェルスクリプトからDOS改行でファイルを区別する方法
どうすればこの決定を下すことができますか?このようfile
などの外部ツールに頼って回避
入力ファイルの行がDOS(CR/LF)またはUnix(LF)改行で終わるかどうかを判断するシェルスクリプトを作成しようとしています。シェルスクリプトからDOS改行でファイルを区別する方法
どうすればこの決定を下すことができますか?このようfile
などの外部ツールに頼って回避
一つの方法は次のとおりです。bashで(ないPOSIXのSHが)、$'\r'
は、キャリッジリターン(CR)文字の構文は次のとおりであるので
#!/bin/bash
# ^^^^- important! not /bin/sh, and do not run with "sh scriptname"
# if given a command-line argument, redirect from it as stdin
if [ -n "$1" ]; then
exec <"$1" || exit
fi
# Read a single line from stdin into a variable
if ! IFS= read -r line; then
# we were unable to read a line
echo "Invalid or Empty"
exit 1
fi
# Check whether the last character of that line is a CR
case $line in
*$'\r') echo "DOS" ;;
*) echo "UNIX" ;;
esac
これは動作します。 read
は最初に見たLFまで読み込むので、DOSファイルでは、そのファイルから読み込まれた行の最後の文字はCRになります。
良い解決策ですが、OPが求めたものとは正確に一致しません。私が質問を正しく理解していれば、ファイル*がLFかCRLFで終わっているかどうか、あなたがチェックしている間は*最初の* LFの前にCRがあるかどうかです。これは、入力ファイルがバイナリファイル、または行末が混在しているファイル(LFとCRLF)、または最後の行に行末マーカーがないファイルの場合に違いがあります。 – user1934428
@ user1934428 OPの元々の質問をチェックするのは面倒ですが、トピックタイトルで示唆されているように、「各行がどこで終わったのか」という意味に解釈されてしまいます。 – tripleee
@ user1934428私の怠惰を克服し、編集された質問のあいまいさを修正しました。実際、OPは最初にファイルの行末を特定することについて尋ねました。 – tripleee
あなたはこれが変数last2でyour_fileの最後の2バイトの16進表現を格納
last2=`tail -c 2 your_file | od -x -A n`
で開始することができます。唯一の問題はバイトオーダです。ビッグエンディアンマシンでは0a0d、リトルエンディアンマシンでは0d0aとなります。
今、あなたはあなたのハードウェアのエンディアンに応じて、あなたのテストを書くことができいずれか、または最初の行を調べることは十分である場合は、
if [ $last2 = 0a0d -o $last2 = 0d0a ]
then
# Cheating! If the file ends in LFCR, it would incorrectly
# say that it is CRLF
echo File ends in CRLF
fi
これは、最終行終了マーカーを持たないDOSファイルではうまく動作しません。 – tripleee
真実ですが、正直なところ:目標が実際にDOSファイルであるかどうかを知るためには、@ John1024が示唆したように、最も安全な方法は 'file'ユーティリティに依存することです。あなたのアプローチでも、そのファイルがそのストリームに0x0dおよび/または0x0aを持つバイナリファイルであれば、問題に遭遇します。しかし、どのような場合でも、なぜこの分類が必要であるかを知ることは有用です。 – user1934428
をカンニングして書くことができ、
perl -ne 'exit ($_ =~ /\r$/)' file
のようなものバッシュでも同じことができます。
lffile() {
local REPLY
read -r <"$1"
case $REPLY in *$'\r') return 1;; *) return 0;; esac
}
これはバッシュの$'\r'
Cスタイルの文字列を必要と> = 3.xのスクリプトにリテラルキャリッジリターン文字を確実かつ移植可能に埋め込むことができれば、それに微妙な変更を加えてsh
を使用することもできます。 、ファイルは、混合行末を持つことができる最も一般的なケースでは
lffile_cr=$(printf '\r')
lffile() {
# local is not POSIX; simply overwrite REPLY
read -r <"$1"
case $REPLY in *"$lffile_cr") return 1;; *) return 0;; esac
}
が、我々が想定した場合、その行末は、一貫性のある(および/または取得することを、次のとおりです。以下は、復帰文字を保持するために厄介なグローバル使用していますそのあいまいなコーナーケースの50%ヒット率またはミス率は許容されます)、最初の行を読むだけで十分です。
if []内でecho "ASCII"を使用し、else内でecho "CR/LF"を使用することができます –
'file'はこの情報などを提供します。それを再発明する魅力的な理由はありますか? – John1024
ところで - ここでの私の編集は重い手で行われましたが、サイトルールで許可されている質問も必要です。 「自分のプログラムを私のために書いてください」という質問に非常に戸惑っています。あなたの目標を達成しようとする際に遭遇した技術的問題に特に焦点を当てるべきです。 –