誰かがこれを達成するためのエレガントな方法を提案できますか?
入力:
test instant ()
test instant ()
...
test instant () //total 1000 lines
出力は次のようになります。
test instant1 ()
test instant2 ()
test instant1000()
空の行が入力ファイルにあり、同じディレクトリの下に一度に処理する必要のあるファイルがたくさんあります。
同じディレクトリにある多くのファイルを置き換えるためにこれを試してみましたが、機能しませんでした。
for file in ./*; do Perl -i -000pe 's/instance$& . ++$n/ge' "$file"; done
エラー:
Substitution replacement not terminated at -e line 1.
Substitution replacement not terminated at -e line 1.
そして私もこれを試しました:Perl -i -pe 's/instant/$& . ++$n/ge' *.vs
それは機能しましたが、インデックスは1つのファイルから別のファイルに増分し続けました。差分ファイルの場合、それを1にリセットしたいと思います。何か良い提案はありますか?
find . -type f -exec Perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +
動作しますが、他のすべてのファイルは置き換えられません。ファイルを「* .txt」のみに置き換えることを好みます。
Perl -pe 's/instant/$& . ++$n/ge'
またはGNU awk
:
awk -vRS=instant '{$0=n$0;ORS=RT}++n'
ファイルをその場で編集するには、Perl
に-i
オプションを追加します。
Perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' ./*
または再帰的に:
find . -type f -exec Perl -pi -e 's/instant/$& . ++$n{$ARGV}/ge' {} +
Perl -pe 's/instant/$& . ++$n/ge'
-p
は、入力を1行ずつ処理し、-e
に渡された式を行ごとに評価して出力します。各行について、(s/re/repl/flags
演算子を使用して)instant
をそれ自体($&
)と変数++$n
の増分値に置き換えます。 g
フラグは、置換をグローバルに(一度だけではなく)行うためのものであり、e
は、置換がPerlコードとして解釈されるように e̲評価(固定文字列ではない)。
1回のPerl呼び出しで複数のファイルを処理するインプレース編集の場合、$n
を各ファイルでリセットする必要があります。代わりに、$n{$ARGV}
を使用します($ARGV
は現在処理されているファイルです)。
awk
の1つは少し説明に値します。
awk -vRS=instant '{$0=n$0;ORS=RT}++n'
GNU awk
の機能を使用して、任意の文字列(正規表現も含む)のレコードを分離します。-vRS=instant
を使用して、r̲ecord s̲eparator to instant
。RT
はRS
と一致したものを保持する変数であるため、通常、instant
は最後のレコードを除いて上記の入力では、レコード($0
)とレコードターミネータ(RT
)は([$0|RT]
)です。
[test |instant][ ()
test |instant][ ()
...
test |instant][ () //total 1000 lines|]
したがって、最初のレコードを除くすべてのレコードの先頭にインクリメントする番号を挿入するだけです。
これが、私たちが上記で行っていることです。最初のレコードの場合、n
は空になります。 ORS(o̲utput r̲ecord s̲eparator)をRTに設定して、awk
がn $0 RT
を出力するようにします。 2番目の式(++n
)で実行されます。これは常にtrue(ゼロ以外の数値)と評価されるため、デフォルトのアクション($0 ORS
の出力)がすべてのレコードに対して実行されます。 。
sed
は実際にはジョブに最適なツールではありません。より優れたスクリプト機能を備えたものが必要です。ここにいくつかの選択肢があります:
Perl
Perl -000pe 's/instant/$& . $./e' file
-p
は、-e
で指定されたスクリプトを適用した後、「すべての行を印刷する」ことを意味します。 -000
は「段落モード」をオンにするので、レコード(行)は連続する改行(\n
)文字で定義され、これにより2重スペース行を正しく処理できます。 $&
は最後に一致したパターンで、$.
は入力ファイルの現在の行番号です。 s///e
のe
を使用すると、置換演算子の式を評価できます。
awk(これは、データが示されているとおりであり、3つのスペースで区切られたフィールドがあることを前提としています)
awk '{if(/./) print $1,$2 ++k,$3; else print}' file
ここでは、現在の行が空でない場合にのみk
変数k
をインクリメントします/./
この場合、必要な情報も出力します。空の行はそのまま印刷されます。
さまざまなシェル
n=0; while read -r a b c; do
if [ "$a" ] ; then
(( n++ ))
printf "%s %s%s %s\n" "$a" "$b" "$n" "$c"
else
printf "%s %s %s\n" "$a" "$b" "$c"
fi
done < file
ここで、各入力行は空白で自動的に分割され、フィールドは$a
、$b
および$c
として保存されます。次に、ループ内で、$c
は、$a
が空でない各行に対して1ずつ増加し、その現在の値が2番目のフィールド$b
の横に出力されます。
注:上記のすべてのソリューションは、ファイルのall行が同じ形式であることを前提としています。そうでない場合、@ Stephaneの答えは、進むべき道です。
多くのファイルを処理し、これを現在のディレクトリ内のallファイルに対して実行する場合は、次のように使用できます。
for file in ./*; do Perl -i -000pe 's/instant/$& . $./e' "$file"; done
注意:スペースのない単純なファイル名を想定しています。より複雑なものを処理する必要がある場合は、次のようにしてください(ksh93
、zsh
またはbash
を想定):
find . -type f -print0 | while IFS= read -r -d ''; do
Perl -i -000pe 's/instant/$& . $./e' "$file"
done