ファイルを変更せずにCRLFまたはLFを使用するかどうかをテストするにはどうすればよいですか?


48

一部のテキストファイルがLinuxモードで保持されるようにするコマンドを定期的に実行する必要があります。残念ながらdos2unix、ファイルは常に変更されます。これにより、ファイルとフォルダーのタイムスタンプが台無しになり、不要な書き込みが発生します。

私が書いたスクリプトはBashにあるので、Bashに基づいた回答を好むでしょう。

回答:


41

dos2unixフィルタとして使用し、その出力を元のファイルと比較できます。

dos2unix < myfile.txt | cmp -s - myfile.txt

2
最初または数行だけでなく、完全なファイルをテストするため、非常にスマートで便利です。
ハレレオ

2
たぶん、あなたは置き換えることができますtestによってmyfile.txtとの混同を避けるために、あなたの例では二回/usr/bin/test
ペテルリーノ

1
注:-s出力を表示するには、フラグを削除する必要があります。manページから: -s, --quiet, --silent suppress all normal output
tobalr

24

目標はただのタイムスタンプへの影響を避けるのであれば、dos2unix持っている-kか、--keepdate同じタイムスタンプを維持するオプションを選択します。一時ファイルを作成して名前を変更するために書き込みを行う必要がありますが、タイムスタンプは影響を受けません。

ファイルの変更が受け入れられない場合は、この回答から次の解決策を使用できます。

find . -not -type d -exec file "{}" ";" | grep CRLF

1
文字通り、CRLFを4文字のC、R、L、Fとして書くということですか?
bodacydo

7
また、grepはそのようにCRとLFを取ることができるということですか?
bodacydo

@bodacydo彼のリンク先の回答で説明されており、スコットのBertSの回答のここunix.stackexchange.com/a/79708/59699でも説明されています。
dave_thompson_085

@ dave_thompson_085説明がわかりません。CRLFについてのみ言及していますが、それが何であるかを説明していません。
bodacydo

1
@bodacydo stackoverflow.com/questions/73833/...は と言うfind ... -exec file ... | grep CRLFDOSの改行コードを含むファイル(すなわちバイト0D 0A)のために、「あなたのような何かを得るだろう:./1/dos1.txt: ASCII text, with CRLF line terminators あなたは、これは実際の文字列CRLFが含まれているためで一致している見ることができるようにgrep探しています単純な文字列CRLF
dave_thompson_085

22

あなたはgrepCRLFコード、8進数を試すことができます:

grep -U $'\015' myfile.txt

または16進数:

grep -U $'\x0D' myfile.txt

もちろん、これはテキストファイルであることを前提としています。
mdpc

2
Iこのようなgrep使用方法、それは私が簡単にディレクトリ内のすべてのこのようなファイルを一覧表示することができますので、grep -lU $'\x0D' *とに出力を渡しますxargs
メレビウス

検索パターンの前の$の意味は何ですか?@don_crissti
fersarr

1
@fersarr-unix.stackexchange.com/ a
don_crissti


13

最初の方法(grep):

キャリッジリターンを含む行をカウントします。

[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos

キャリッジリターンで終わる行をカウントします。

[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos

これらは通常同等です。行の内部での復帰(つまり、最後ではない)はまれです。

より効率的な:

grep -q $'\r' myfile.txt && echo dos

これはより効率的です

  1. カウントをASCII文字列に変換し、その文字列を整数に変換してゼロと比較する必要がないためです。
  2. grep -cパターンのすべてのオカレンスをカウントするためにファイル全体を読み取る必要があるため、パターンgrep -qの最初のオカレンスを見たときに終了できます。

ノート:

  • GNU はファイルがテキストファイルであるかどうかを推測するため、上記全体を通して、-Uオプション(つまり、-cUまたは-qU)を追加する必要がある場合がありgrepます。ファイルがテキストであると考えられる$場合、正規表現が「正しく」動作するように、正規表現が\r$!であっても、行末の復帰を無視します。指定すると-U(または--binary)この当て推量が無効になりgrep、ファイルがバイナリとして扱われ、CR終了がそのままの状態でデータが一致するメカニズムに逐語的に渡されます。
  • しないでください。パターン区切り文字として扱われるgrep … $'\r\n' myfile.txtためです。同じように含む行を探しますかnull文字列、 含む行を探しますかnull文字列、およびすべての行はヌル文字列にマッチします。grep\ngrep -E 'foo|'foogrep $'\r\n'\r

2番目の方法(file):

[[ $(file myfile.txt) =~ CRLF ]] && echo dos

fileようなものを報告するため:

myfile.txt: UTF-8 Unicode text, with CRLF line terminators

より安全なバリアント:

[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos

どこ

file 英語以外のロケールでは、からの出力のチェックが機能しない可能性があることに注意してください。


1
個人的には誤検知の数を減らすために使用しますが"$(echo -e '\r')"、もっと単純なものに置き換えることができます。$'\r'$'\r\n'
リチ

@rici grep $'\r\n'は私のシステム上のすべてのファイルと一致するようです
...-depquid

@rici:良いキャッチ。あなたの提案に従って答えを編集しました。— depquid:おそらくWindowsを使用していますか?:-) riciのヒントがここで機能します。
バート

@depquid(およびBertS):実際にはgrep -U $'\r$'grep行末を推測することを防ぐため、正しい呼び出しはであると思います。
リチ

また、-q一致するものが見つかった場合-cは、追加のチェックが必要になる代わりに、戻りコードを設定するだけに使用できます。個人的には2番目のソリューションが好きですが、それは気まぐれに大きく依存しており、file英語以外のロケールでは機能しない可能性があります。
リチ

11

つかいます cat -A

$ cat file
hello
hello

このファイルが* NIXシステムで作成された場合、次のように表示されます。

$ cat -A file
hello$
hello$

しかし、このファイルがWindowsで作成された場合、表示されます

$ cat -A file
hello^M$
hello

^M表すCR$表しますLF。Windowsは最後の行を保存していないことに注意してくださいCRLF

ファイルの内容も変更されません。


最良かつ最も簡単なソリューション!より多くの賛成票が必要です。
user648026

1
+1最高の答え。依存関係も複雑なbashスクリプトもありません。ただ-A猫に。ただしcat -A file | less、ファイルが大きすぎる場合に使用するのが1つのヒントです。特に長いファイルについては、ファイルの末尾を確認する必要があることは珍しくありません。(q少なくするために押してください)
ニコラス・ピピトーン

4

あなたのためのbash関数:

# return 0 (true) if first line ends in CR
isDosFile() {
    [[ $(head -1 "$1") == *$'\r' ]]  
}

その後、次のようなことができます

streamFile () {
    if isDosFile /tmp/foo.txt; then
        sed 's/\r$//' "$1"
    else
        cat "$1"
    fi
}

streamFile /tmp/foo.txt | process_lines_without_CR

3
isDosFile()例で使用する必要はありません:streamFile() { sed 's/\r$//' "$1" ; }

1
これが最もエレガントなソリューションだと思います。ファイル全体ではなく、最初の行のみを読み取ります。
アダムリツコフスキ

4

ファイルにDOS / WindowsスタイルのCR-LF行末がある場合、Unixベースのツールを使用してファイルを見ると、各行の終わりにCR( '\ r')文字が表示されます。

このコマンド:

grep -l '^M$' filename

filenameファイルにWindowsスタイルの行末を持つ1つ以上の行が含まれている場合は印刷し、含まれていない場合は何も印刷しません。^Mがリテラルの復帰文字でなければならないことを除いて、通常はCtrl+にV続けてEnter (またはCtrl+ VしてからCtrl+ M)と入力して端末に入力します。bashシェルを使用すると、リテラルのキャリッジリターンを$'\r'ここに記載)として記述できるため、次のように記述できます。

grep -l $'\r$' filename

他のシェルも同様の機能を提供します。

代わりに別のツールを使用できます。

awk '/\r$/ { exit(1) }' filename

これは、のステータスで終了します1(設定$?1ファイルを任意のWindowsスタイルの改行コードが含まれている場合)、およびの状態で0、それはシェルで、それが有用なものと、しない場合ifの文(の欠如に注意[ブラケット]):

if awk '/\r$/ { exit(1) }' filename ; then
    echo filename has Unix-style line endings
else
    echo filename has at least one Windows-style line ending
fi

ファイルには、UnixスタイルとWindowsスタイルの行末を混在させることができます。ここでは Windowsスタイルの行末を持つファイルを検出することを想定しています。


1
$'\r'この質問に対する他の回答で述べたように、コマンドラインでbash(および他のいくつかのシェル)でキャリッジリターンをエンコードできます。
スコット

2

使用file

$ file README.md
README.md: ASCII text, with CRLF line terminators

$ dos2unix README.md
dos2unix: converting file README.md to Unix format...

$ file README.md
README.md: ASCII text

このアイデアは、以前の2つの回答でさらに詳しく説明されています。
G-Manが「Reinstate Monica」と言う

1

私は使っています

cat -v filename.txt | diff - filename.txt

うまくいくようです。出力は読むよりも少し簡単だと思う

dos2unix < filename.txt | diff - filename.txt

dos2unix何らかの理由でインストールできない場合にも便利です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.