2016-07-26 5 views
0

入力ファイルの行がDOS(CR/LF)またはUnix(LF)改行で終わるかどうかを判断するシェルスクリプトを作成しようとしています。シェルスクリプトからDOS改行でファイルを区別する方法

どうすればこの決定を下すことができますか?このようfileなどの外部ツールに頼って回避

+0

if []内でecho "ASCII"を使用し、else内でecho "CR/LF"を使用することができます –

+2

'file'はこの情報などを提供します。それを再発明する魅力的な理由はありますか? – John1024

+0

ところで - ここでの私の編集は重い手で行われましたが、サイトルールで許可されている質問も必要です。 「自分のプログラムを私のために書いてください」という質問に非常に戸惑っています。あなたの目標を達成しようとする際に遭遇した技術的問題に特に焦点を当てるべきです。 –

答えて

1

一つの方法は次のとおりです。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になります。

+0

良い解決策ですが、OPが求めたものとは正確に一致しません。私が質問を正しく理解していれば、ファイル*がLFかCRLFで終わっているかどうか、あなたがチェックしている間は*最初の* LFの前にCRがあるかどうかです。これは、入力ファイルがバイナリファイル、または行末が混在しているファイル(LFとCRLF)、または最後の行に行末マーカーがないファイルの場合に違いがあります。 – user1934428

+1

@ user1934428 OPの元々の質問をチェックするのは面倒ですが、トピックタイトルで示唆されているように、「各行がどこで終わったのか」という意味に解釈されてしまいます。 – tripleee

+1

@ user1934428私の怠惰を克服し、編集された質問のあいまいさを修正しました。実際、OPは最初にファイルの行末を特定することについて尋ねました。 – tripleee

0

あなたはこれが変数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 
+0

これは、最終行終了マーカーを持たないDOSファイルではうまく動作しません。 – tripleee

+0

真実ですが、正直なところ:目標が実際にDOSファイルであるかどうかを知るためには、@ John1024が示唆したように、最も安全な方法は 'file'ユーティリティに依存することです。あなたのアプローチでも、そのファイルがそのストリームに0x0dおよび/または0x0aを持つバイナリファイルであれば、問題に遭遇します。しかし、どのような場合でも、なぜこの分類が必要であるかを知ることは有用です。 – user1934428

1

をカンニングして書くことができ、

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%ヒット率またはミス率は許容されます)、最初の行を読むだけで十分です。

関連する問題