web-dev-qa-db-ja.com

sed / awkで一致する番号を検索/置換およびインクリメントする方法は?

ポイントにまっすぐ、私はgrep/find/sed/awkを使用して特定の文字列(数字で終わる)を一致させ、その数字を1ずつ増やす方法を疑問に思っています。目的(これは十分に機能します)の主な目的は単純に値を変更することです。私が現在していることは次のとおりです。

find . -type f | xargs sed -i 's/\(\?cache_version\=[0-9]\+\)/\11/g'

数値をインクリメントする方法がわからなかったため、すべてをキャプチャし、「1」を追加しました。以前は、次のようなものがありました。

find . -type f | xargs sed -i 's/\?cache_version\=\([0-9]\+\)/?cache_version=\11/g'

したがって、少なくとも必要なものをキャプチャする方法は理解しています。

これが何のためであるかを説明する代わりに、私はそれが何をしたいのかだけを説明します。現在のディレクトリに基づいて、再帰的に、任意のファイル内のテキストを検索する必要があります(重要ではありません。任意のディレクトリになる可能性があるため、後で構成します)。次に、その番号をインクリメントし、ファイル内で置き換えます。

現在、上記のものは動作しますが、最後に見つかった数を増やすことはできません。将来の値が「11」、「111」、「1111」、「11111」などにならないように、「1」を追加する代わりに増分できるとよいでしょう。

私は何十もの記事/説明を経験しましたが、多くの場合、提案はawkを使用することですが、私の人生ではそれらを混ぜることはできません。実際に何も置き換えないawkを使用することに最も近づいたのは次のとおりです。

grep -Pro '(?<=\?cache_version=)[0-9]+' . | awk -F: '{ print "match is", $2+1 }'

最後にsedをパイプして元のファイル名を渡す方法があり、sedがファイル名と増分番号(awkから)を持つことができるかどうか、またはxargsが必要とするものは何でも。

技術的には、この数値は重要ではありません。この置換は主に、そこに新しい番号が存在することを確認するためのもので、確かに最後のものとは100%異なります。したがって、この質問を書いているときに、エポックからのシステム時間(秒= AJAXが後続の「同一の」リクエストのキャッシュを排除するためによく使用する手法)これで終わり、それは完璧なようです:

CXREPLACETIME=`date +%s`; find . -type f | xargs sed -i "s/\(\?cache_version\=\)[0-9]\+/\1$CXREPLACETIME/g"

(何らかの理由で複数の秒にまたがる場合に備えて、すべてのファイルが同じ値を取得するように値を最初に保存します)

しかし、一致した数を増やす際の元の質問を知りたいと思っています。私は簡単な解決策はそれをbashスクリプトにすることだと思いますが、それでも、すべてのファイルを再帰的にループし、その内容をチェックしてから置換するよりも簡単な方法があると思いました...他にあまりロジックはありません。他のファイルやそのようなものに書き込みたくない-sedが "i"オプションで行うように、適切な場所に書き込む必要があります。

37
Ian

ファイルを見つけることはあなたにとって難しいことではないと思います。したがって、+ 1の計算を行うためにポイントに移動します。 gnu sedがある場合、次のようにできます。

sed -r 's/(.*)(\?cache_version=)([0-9]+)(.*)/echo "\1\2$((\3+1))\4"/ge' file

例を見てみましょう:

kent$  cat test 
Ello
barbaz?cache_version=3fooooo
bye

kent$  sed -r 's/(.*)(\?cache_version=)([0-9]+)(.*)/echo "\1\2$((\3+1))\4"/ge' test     
Ello                                                                             
barbaz?cache_version=4fooooo
bye

必要に応じて-iオプションを追加できます。

編集

/eを使用すると、一致した部分を外部コマンドに渡し、実行結果で置換することができます。 Gnu sedのみ。

この例を参照してください:外部コマンド/ツールechobcが使用されます

kent$  echo "result:3*3"|sed -r 's/(result:)(.*)/echo \1$(echo "\2"\|bc)/ge'       

出力を与える:

result:9

cut、sed(もう一度)、awkなど、他の強力な外部コマンドを使用できます。

54
Kent

純粋sedバージョン:

このバージョンは、他のコマンドや環境変数に依存しません。明示的なキャリングを使用します。キャリーには@記号を使用しますが、必要に応じて別の名前を使用できます。入力ファイルに存在しないものを使用してください。最初にSEARCHSTRING<number>を見つけ、それに@を追加します。保留中の桁上げのある数字のインクリメントを繰り返します(つまり、その後に桁上がり記号があります:[0-9]@)9がインクリメントされた場合、このインクリメントは桁上げを生成し、保留中の桁上げがなくなるまでプロセスを繰り返します。 。最後に、生成されたがまだ数字に追加されていないキャリーは1に置き換えられます。

sed "s/SEARCHSTRING[0-9]*[0-9]/&@/g;:a {s/0@/1/g;s/1@/2/g;s/2@/3/g;s/3@/4/g;s/4@/5/g;s/5@/6/g;s/6@/7/g;s/7@/8/g;s/8@/9/g;s/9@/@0/g;t a};s/@/1/g" numbers.txt
9
Martijn

このPerlコマンドは、現在のディレクトリ内のすべてのファイルを検索し(トラバースせず、File::Findモジュールまたはより複雑なタスクに類似する必要があります)、cache_version=に一致する行の数を増やします。置換部分を評価する正規表現の/eフラグを使用します。

Perl -i.bak -lpe 'BEGIN { sub inc { my ($num) = @_; ++$num } } s/(cache_version=)(\d+)/$1 . (inc($2))/eg' *

次のデータを使用して、現在のディレクトリでfileを使用してテストしました。

hello
cache_version=3
bye

元のファイル(ls -1)をバックアップします。

file
file.bak

そしてfileは次のようになりました:

hello
cache_version=4
bye

あなたが探しているものに役立つことを願っています。


[〜#〜] update [〜#〜]は、ディレクトリの走査にFile::Findを使用します。 *を引数として受け入れますが、File::Findで見つかったものと一緒に破棄します。検索を開始するディレクトリは、スクリプトの実行の現在です。 find( \&wanted, "." )行にハードコーディングされています。

Perl -MFile::Find -i.bak -lpe '

    BEGIN { 
        sub inc { 
            my ($num) = @_; 
            ++$num 
        }

        sub wanted {
            if ( -f && ! -l ) {  
                Push @ARGV, $File::Find::name;
            }
        }

        @ARGV = ();
        find( \&wanted, "." );
    }

    s/(cache_version=)(\d+)/$1 . (inc($2))/eg

' *
7
Birei

これはいです(少しさびています)が、sedの使用を開始します。

orig="something1" ;
text=`echo $orig | sed "s/\([^0-9]*\)\([0-9]*\)/\1/"` ;
num=`echo $orig | sed "s/\([^0-9]*\)\([0-9]*\)/\2/"` ;
echo $text$(($num + 1))

元のファイル名($orig)「something1」のsedは、テキスト部分と数値部分を$textおよび$num、これらは最後のセクションでインクリメントされた番号と結合され、something2

ファイル名に数字が含まれる場合や末尾に数字が含まれない場合は考慮されませんが、sedを使用するという当初の目標に役立つことを願っています。

これは実際にはバッファーを使用することでsed内で単純化できます(sedは再帰的に動作できます)が、私は本当にその側面にさびています。

3
David Ravetti