正規表現が含まれている場合、sed でファイルをスキップするにはどうすればよいですか?

正規表現が含まれている場合、sed でファイルをスキップするにはどうすればよいですか?

現在、私は以下を使用しています簡略化されたコマンド末尾の空白を削除するそしてファイルの最後に改行を追加する必要な場合:

find . -type f -exec sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' {} \+

すぐにわかるように、これには2つの問題があります。バイナリファイルそして、ファイルの末尾に改行を追加します。␍␊ 行区切りこれらの変更はコミット時に簡単に元に戻したりスキップしたりできますgit guiが、元に戻す回数を最小限に抑えたいと考えています。そのためには、次の操作を行います。

スキップする方法はありますか?全体ファイルの場合どれでもsed行は?内の正規表現と一致します。

* バイナリファイルには␀文字が含まれていない可能性があり、意図的に改行や␀が混在しているファイルもあることは承知しています。しかし、私は人間の介入を最小限に抑える解決策を探しています。できたおそらく、操作したいファイル拡張子をすべてリストすることになりますが、リストが非常に長くなり、常に確認する必要があり、名前の衝突によりバイナリ ファイルが漏れてしまう可能性が依然としてあります。

複雑回避策:

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

答え1

gitバイナリ ファイルかどうかに関する の見解を信頼している場合は、 を使用しgit grepて非バイナリ ファイルのリストを取得できます。t.cppがテキスト ファイルで、 がlsバイナリであると仮定すると、両方ともチェックインされています。

$ ls
t.cpp ls
$ git grep -I --name-only -e ''
t.cpp

オプション-Iの意味は次のとおりです。

-I
バイナリ ファイル内のパターンを一致させないでください。

sedこれをあなたの表現と組み合わせるには:

$ git grep -I --name-only -z -e '' | \
       xargs -0 sed -i.bk -e 's/[ \t]\+\(\r\?\)$/\1/;$a\'

( -z/ はxargs -0奇妙なファイル名に役立ちます。)

git grepその他の便利なオプションについては、man ページを参照してください。--no-indexまた、--cached操作するファイルのセットに応じて役立つ場合もあります。

答え2

いずれかの行が sed の正規表現に一致する場合にファイル全体をスキップする方法はありますか?

はいあります。

# test case for skipping file if a sed regex match succeeds

echo 'Hello, world!' > hello_world.txt
cat hello_world.txt
ls -li hello_world.txt

sed -i -e '/.*Hello.*/{q;}; s/world/WORLD/g' hello_world.txt # skips file
sed -i -e '/.*HeLLo.*/{q;}; s/world/WORLD/g' hello_world.txt

答え3

以下は、引数 (ファイル名である必要があります) を反復処理し、改行で終わらないすべてのファイルに改行を追加する Perl スクリプトです。ヌル バイトを含むファイルはスキップされます。すでに改行で終わるファイルは変更されません。CR を含むファイルには CRLF が追加され、その他のファイルには LF のみが追加されます。テストされていません。

#!/usr/bin/env perl
foreach my $f (@ARGV) {
    open F, "<", $f or die;
    my $last = undef;
    my $cr = 0;
    while (<>) {if (/\0/) {undef $last; break} $last = $_; ++$cr if /\r$/}
    close F;
    if (defined $last && $last !~ /\n\Z/) {
        open F, ">>", $f or die;
        print($cr ? "\r\n" : "\n");
        close F or die;
    }
}

関連情報