file1 の M 行を file2 の N 行に置き換えます。

file1 の M 行を file2 の N 行に置き換えます。

Let M=3and 。ライン入力をライン入力に変更しN=4たいです。以下を使用して文字列を置き換えることができます。Mfile1Nfile2sed

sed -i '3s/.*/stringToReplace/' file1

私はこれを使ってawk行を得ることができますNfile2

awk 'NR==4' "file2"

これら2つをどのように組み合わせることができますか?試してみると

sed -i '3s/.*/{awk 'NR==4' "file2"}/' file1

次に、Mlineを文字通りの意味に置き換えます{awk 'NR==4' "file2"}

答え1

任意の入力を処理するためにこれを正しく実行する方法はいくつかあります。
GNUsedと以下をサポートするシステムを使用してください/dev/stdin

sed -n "${n}{p;q;}" file2 | sed -e "$m{r/dev/stdin" -e 'd;p;}' file1

または少し短い1

sed $n'!d;q' file2 | sed -e $m'{r /dev/stdin' -e 'd;p;}' file1

sedプロセスの交換をサポートするシェルを使用してください。

sed '1h;1d;'$((m+1))'x' <(sed ${n}'!d;q' file2) file1

次のように書くこともできます。

sed ${n}'!d;q' file2 | sed '1h;1d;'$((m+1))'x' - file1

デフォルトでは、1回のsed呼び出しは行を抽出し、別の呼び出しnからfile2最初のオペランドに読み込みますsed。これを保持バッファに保存して削除し、2番目のオペランドの内容を読み込みます。つまりfile1、交換時にラインでバッファm+1(入力結合))。

sed以下を介してスクリプトファイルの読み取りをサポートしている人:-fstdin

sed ${n}'!d;i\
'${m}'c\\
s/\\/&&/g
q' file2 | sed -f - file1

ここで最初のsedものは、行を次のスクリプトファイルnに置き換えます。file2

${m}c\
line_n_content_here_with_any_backslash_escaped

次に、2番目の項目のsed処理に使用されますfile1(例:その行をm次のテキストに置き換えます。)。 anyを使用しa\たりテキストを追加したりするときなど、元のテキスト内のすべてのバックスラッシュ(含まれている改行も含みますが、ここには1つのみ)をエスケープする必要がありますi\c\

<backslash> characters in text shall be removed, and the following character shall be treated literally.

いずれにせよ、sed常に人気のあるs代替コマンドを使用できます。sed挿入された代替文字列がすべての予約文字をエスケープしていることを確認してください。- この特別な場合には1行です。

line=$(sed ${m}'!d;s|[\/&]|\\&|g;q' file2)

次に、次のものを交換します。

sed ${m}'s/.*/'"$line"'/' file1

大規模な入力ファイルの場合は、以下を実行できます。

{ head -n $((m-1)); { head -n $((n-1)) >/dev/null; head -n 1; } <file2; head -n 1 >/dev/null; cat; } <file1

これは次のことを行います。

print (m-1) lines from file1
discard (n-1) lines from file2
print n-th line from file2
discard m-th line from file1
print the remaining lines from file1

何人かのhead人々は愚かで何をすべきかわからないが標準準拠したがって、これがすべての設定で機能するわけではありませんが、それが機能している場合はsed速度の面で優れています。awk


1:一部のシェルでは、これが機能するために履歴拡張を無効にする必要があるかもしれません!...
また、正の整数でなければならないので、ここで引用する必要はありません$n$m

答え2

この試み:

$ cat f1
foo
bar
xyz
baz
temp
good
$ cat f2
1
2
3
4
5
6

$ awk -v m=3 -v n=4 'NR==FNR{if(FNR==n) s=$0; next} FNR==m{$0=s} 1' f2 f1
foo
bar
4
baz
temp
good
  • NR==FNR最初のファイルが処理されている場合にのみ真
  • if(FNR==n) s=$0n番目の行を減らすと変数に保存
  • nextこれにより、最初のファイルの処理中に残りのコードは実行されません。
  • FNR==m{$0=s}2番目のファイルパラメータのm行目の場合は置き換えます。
  • 1修正を含む入力履歴を印刷します。
  • ファイル入力パラメータの順序に注意してください。

if(FNR==n){s=$0;nextfile}n行目以降のライン処理を避けるために使用できます。

~からGNU awk マニュアル-ありがとう@iruvar

注:nextfileは長年にわたって一般的な拡張機能でした。 2012年9月にPOSIX規格に統合されました。オースティングループのウェブサイトをご覧ください。

答え3

短いsed方法:

サンプルファイルf1:

f1 line1
f1 line2
f1 line3
f1 line4
f1 line5

サンプルファイルf2:

ID1,value12,value13
ID1,value22,value23
ID1,value32,value33
ID2,/value42/,~value43~
ID3,value52,value53

働く:

sed '3 s/.*/'"$(sed -n '4{ s/\//\\\//g;p;}' f2)"'/;' f1

出力:

f1 line1
f1 line2
ID2,/value42/,~value43~
f1 line4
f1 line5

答え4

awkとsedを混ぜないでください。完全なawkソリューションが利用可能

ファイル1:

 file1 1
 file1 2
 file1 3
 file1 4

ファイル2:

 file2 1
 file2 2
 file2 3
 file2 4


 awk -v m=3 -v n=4 'NR == FNR { filea[FNR]=$0 } FNR != NR { fileb[FNR]=$0 } END { for (i=1;i<=FNR;i++) { if ( i == m ) { print fileb[n] } else { print filea[i] } } } ' file1 file2

分割:

 NR == FNR { 
            filea[FNR]=$0 
           }
 FNR != NR { 
            fileb[FNR]=$0 
           }
 END { 
       for (i=1;i<=FNR;i++) { 
                               if ( i == m ) { 
                                         print fileb[n] 
                                             } 
                               else { 
                                          print filea[i] 
                                    } 
                            } 
      } 

NRとFNRを比較して、file1とfile2のレコードを決定します(NR = FNRの場合は最初のファイルにあることがわかります)。 file1のレコードとしてfilea配列を設定し、file2のレコードとしてfileb配列を設定しました。次に、filea配列のすべてのレコードを繰り返し、渡されたパラメータmが3以外の場合にのみ内容を印刷します。そうであれば、渡されたパラメータnによって決定された配列ファイルの添え字を印刷します。

関連情報