行番号がファイルに保存されたら、複数行を文字列に置き換えます。

行番号がファイルに保存されたら、複数行を文字列に置き換えます。

数百万行のファイルがありますが、すべて同じです。 1つの例は次のとおりです。

Known
Known
Known
Known
Known
Known
...

何千もの行番号を含む別のファイルがあります。たとえば、次のようになります。

3
5
6
...

UnKnownなどのbashコマンドを使用してこの行を別の文字列に置き換える簡単な方法があるかどうか疑問に思います。作成する例に基づいて、次の操作を行います。

Known
Known
UnKnown
Known
UnKnown
UnKnown
...

答え1

解決策awk

$ awk 'NR==FNR{a[$1]++;next}
       { 
        if(FNR in a){
            print "UnKnown"
        }
        else{
            print
        }
       }' nums file
Known
Known
UnKnown
Known
UnKnown
UnKnown

説明する

  • NR==FNR{a[$1]++;next}: はNR入力の現在行番号、FNR現在のファイルの現在行番号です。 2 つは、最初のファイルを読み取る場合にのみ同じです。したがって、この式は各行$1番号(最初のファイルの最初のフィールド)を配列のキーとして保存し、次の行に移動しますa
  • if(FNR in a){ print "UnKnown"}:現在のファイルの行番号が最初のファイルにある場合は、「UnKnown」を印刷します。
  • else {print}:そうでない場合は、現在の行を印刷します。

答え2

これは、「変更する行数が少ない場合」シナリオに対するGilesの回答のバリエーションです。インライン sed 式を作成する代わりに、-f - を使用して stdout/stdin を介して sed に読み込まれる sed スクリプトを作成します。これにより、コマンドラインの長さの制限に関する問題を回避できます。あるいは、sedスクリプトを "temp"ファイルに保存し、sedがそのファイルを指すこともできます。

私が紹介したもう一つのバリエーションはsedの "c"コマンドです。これは、選択した行を指定されたテキストに置き換えることを意味します。 "c"コマンドの構文は、バックスラッシュ、改行、新しいテキストが必要であるという点で少し変わります。

sed 's/$/c\\\nNew String/' line-number-file | sed -f - input-file > output-file

$最初のsedコマンドは、行末()を「c、バックスラッシュ、改行、新しい文字列」の順に「置換」し、2番目のsedへの入力として中間sedスクリプトを作成します。

3c\
New String
5c\
New String
6c\
New String

代替テキストとして使用されるテキストを変更するには、最初のsedセクションに移動して「New String」を希望のものに置き換えます。

ソース入力ファイルのテキストを置き換え、sed が対応するフラグをサポートして-iいる場合は、コマンドを次のように変更できます。

sed 's/$/c\\\nNew String/' line-number-file | sed -f - -i input-file

答え3

1つの可能性は、awkを介して行をフィルタリングすることです。変更したい行のリストが小さい場合は、コマンドラインからawkに渡してください。

awk <original.txt >modified.txt -v lines="$(cat lines-to-change.txt)" '
    BEGIN {split(lines, a); for (i in a) change[a[i]]=1}
    NR in change {$0 = "Un" $0} # or $0 = "UnKnown"
    1
'

変更する回数が非常に少なく、変更するファイルが非常に大きい場合、sed はより速くなる可能性があります。 sedを使用する場合は、各行に適用する代替項目を含むスクリプトを作成する必要があります。

sed "$(<lines-to-change.txt sed 's/$/s:^:Un:/')" <original.txt >modified.txt

行の大部分を変更する必要がある場合は、最初の2つの方法を使用すると、コマンドラインの長さの制限が発生します。これは、2つのファイルを並列に読み取るawkの修正です。すでにソートされている場合は、代わりにlines-to-change.txt使用できます。getline n <"lines-to-change.txt""sort -n lines-to-change.txt" | getline n

awk <original.txt >modified.txt '
    BEGIN {"sort -n lines-to-change.txt" | getline n}
    NR==n {$0 = "Un" $0; n = 0; "sort -n lines-to-change.txt" | getline n}
    1
'

関連情報