パターン(マーカー)の前にファイルのコンテンツを別のファイルに挿入する方法は?


32

File1 内容:

line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 

File2 内容:

line1-file2     "25"  
line2-file2     "24"  
Pointer-file2   "23"  
line4-file2     "22" 
line5-file2     "21"

perl / shellスクリプトの実行後、File2コンテンツは次のようになります。

line1-file2     "25"  
line2-file2     "24" 
line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 
Pointer-file2   "23" 
line4-file2     "22" 
line5-file2     "21"

すなわち、「ポインタ」を含む行の前にFile1in の内容を貼り付けFile2ます。




私はすでにこの理由で終了のSO質問に投票しました。この質問を終了する理由はもうありません。ところで、問題はSOの品質がはるかに悪いため、ロジックはこれではなく、それを閉じるように指示しています。
ペテルはモニカを

回答:


33

sed そのための機能があり、インラインで変更を行うことができます:

sed -i -e '/Pointer/r file1' file2

ただし、これにより、ポインター行がfile1の上に配置されます。それを下に置くには、ライン出力を遅らせます:

sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2 

8
何をするのか説明して-e 1x -e '2,${x;p}' -e '${x;p}'もらえますか?パターンバッファの内容を交換してから印刷することは理解していますが-n、最初にQuietオプションを追加した理由と理由を知りません。
hdl

@ jfg956元のファイルの「ポインタ」部分を置き換えて削除することは可能ですか?これはsedの2回目のスイープで把握できますが、1回実行することは可能ですか?
アレクサンダースカ

17

sedまたはを使用せずにawk...

まず、パターンのある行を見つけます。

line=$(grep -n 'Pointer' file2 | cut -d ":" -f 1)

次に、3つのコマンドを使用して、必要な結果を出力します。

{ head -n $(($line-1)) file2; cat file1; tail -n +$line file2; } > new_file

これにはfileの3倍のアクセスという欠点file2がありますがsedawk解決策よりも明確な場合があります。


10

awkこれはかなり簡単になります。
ファイルの前に行を挿入します。

awk '/Pointer/{while(getline line<"innerfile"){print line}} //' outerfile >tmp
mv tmp outerfile

Pointer行の後に内部ファイルを印刷するには、パターンの順序を切り替えるだけで(デフォルトのアクションを取得するにはセミコロンを追加する必要があります)、line変数をドロップできます。

awk '//; /Pointer/{while(getline<"innerfile"){print}}' outerfile >tmp
mv tmp outerfile

そして、誰もperlまだ使用していないという理由だけで、

# insert file before line
perl -e 'while(<>){if($_=~/Pointer/){system("cat innerfile")};print}' outerfile

# after line
perl -e 'while(<>){print;if($_=~/Pointer/){system("cat innerfile")}}' outerfile

動作しますが、ポインターを含む行が削除されます
-user1228191

同様に、awkを使用して行を含む「ポインタ」の後
user1228191

@ user1228191最初を修正し、2番目を追加しました。
ケビン

「perl」バージョンは機能していないようです。system("cat innerfile")innerfileコンソールに出力します。何か不足していますか?
kaartic

awkコマンド[gawk '/ <body> / {while(getline line <"$ HOME / bin / SrunScenario.style"){print line}} //' index.html> new_index.html]ループし、何百万行も印刷する。gawk V4.2.0ここで何が欠けていますか?
JESii

7

簡単な仕事ed

ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN

-r file1アドレス指定された行の後に指定されたファイルを読み込みます。この場合、これはに一致する最初の行の前の行Pointerです。そのため、複数行で発生したfile2場合でも1回だけコンテンツが挿入さPointerれます。一致する各行の前に挿入する場合は、globalフラグを追加します。

ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN

交換する,pwあなたはその場でファイルを編集する場合。


sedほとんどの場合、受け入れられた答えは機能しますが、マーカーが最後の行にある場合、コマンドは期待どおりに機能しませんFile1。マーカーの後にコンテンツを挿入します。
私は最初に試しました:

sed '/Pointer/{r file1
N}' file2

これも正常に動作します(rサイクルの終わりに魔法を行うように)が、マーカーが最後の行にある場合は同じ問題があります(N最後の行の後にext行はありません)。これを回避するには、入力に改行を追加します。

sed '/Pointer/{              # like the first one, but this time even if the
r file1                      # marker is on the last line in File2 it
N                            # will be on the second to last line in
}                            # the combined input so N will always work;
${                           # on the last line of input: if the line is
/^$/!{                       # not empty, it means the marker was on the last
s/\n$//                      # line in File2 so the final empty line in the
}                            # input was pulled i\n: remove the latter;
//d                          # if the line is empty, delete it
}' file2 <(printf %s\\n)

これによりfile2、一致する各行の前にコンテンツが挿入されます。最初に一致する行の前にのみ挿入するには、loopを使用して、nファイルの終わりに達するまでext行をプルするだけです。

sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)

これらのsedソリューションを使用すると、その場で編集する機能が失われます(ただし、別のファイルにリダイレクトできます)。


6

ループを使用して、file2の行を読み取ります。で始まる行が見つかったらPointer、file1を出力します。これを以下に示します。

#!/bin/bash
while IFS= read -r line
do
    if [[ "$line" =~ ^Pointer.*$ ]]
    then
        cat file1
    fi
    echo "$line"
done < file2

4

このw /については、いくつかの方法がありますsed。1つの方法は、受け入れられた回答で推奨されている遅延読み取りです。次のように書くこともできます。

sed -e '$!N;P;/\nPointer/r file1' -e D file2

...保留バッファを使用して他の場所に実装された後読みの代わりに、少し明示的な先読みを使用します。ただし、@ don_crisstiが指摘する最後の行と同じ問題が必ず発生N ます。これ、行サイクルをインクリメントし、readコマンドが行番号で適用されるためです。

あなたはそれを回避することができます:

echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -

すべてsedのが-標準入力を意味すると解釈するわけではありませんが、多くは解釈します。POSIXは 、実装者が標準入力を意味する場合、標準入力を意味することsedをサポート-する必要があると言います-か?)

別の方法は、追加されたコンテンツを順番に処理することです。ead と同じ方法で出力をスケジュールする別のコマンドがありr、スクリプト化された順序でsedそれを適用してreadを実行します。それが1つを使用して伴う-それは、よりかかわら関与少しだsedaPPEND Pointer別の出力に一致するものをsedそのスクリプトインチ

sed '   /Pointer/!d                  #only operate on first match
        s/[]^$&\./*[]/\\&/g;H        #escape all metachars, Hold
        s|.*|/&/!p;//!d|p;g          #print commands, exchange
        s|.|r file1&a\\&|;q' file2|  #more commands, quit
        sed -nf - file2              #same input file

したがって、基本的に最初のスクリプトsedは2番目sedのスクリプトを記述し、2番目のスクリプトはsed標準入力(おそらく...)で読み取り、順番に適用します。最初sedは、Pointer見つかった、およびその後のquits入力の最初の一致でのみ機能します。その仕事は...

  1. s/[]^$&\./*[]/\\&/g;H
    • 2番目の文字は、文字をsed読み取るたびに文字どおりに解釈する必要があるため、すべてのパターン文字が安全にバックスラッシュでエスケープされていることを確認してください。それが終わったら、H古いスペースにコピーを置きます。
  2. s|.*|/&/!p;//!d|p; x
    • 2番目にsedpすべての入力行をリントするように指示します!が、/&/パターンセーフしたのは1 行だけです。そしてd、同じすべてを選出する。p第二にコマンドをRINT sed、その後、電子x変更h当社保存されたコピーの仕事に古いものとパターンバッファを。
  3. s|.|r file1&a\\&|p;q
    • ここで作業する唯一の文字は、前に行を入力するときに先頭に追加される\nため、ewline です。そのため、コマンドを挿入し、それに続いてewlineを実行し、ppendのコマンドに続いてewlineを実行します。残りのeld行はすべて、最後のewlineに従います。sedHr file1\na\\a\nH\n

最初のスクリプトは次のようになります。

/Pointer-file2   "23"/!p;//!d
r file1
a\
Pointer-file2   "23"

基本的に、2番目のsed行はすべての行を印刷しますが、最初の行sedappendに設定します。その特定の行について、標準出力への2つの遅延書き込みがスケジュールされてます。最初の行はreadでfile1、2番目の行はその後に必要な行のコピーです。sedこの場合、最初のドクターは必要ありません(バックスラッシュなし)。ただし、パターンマッチが入力として再利用される場合は、ここで行うように安全に脱出することが重要です。

とにかく、だから...いくつかの方法があります。


2

AWKを使用すると、これは非常に簡単です。

File1からFile2へ、パターン=「ポインター」の前

最初にFile1の内容を変数にロードします

f1="$(<File1)"

その後、挿入を行います

awk -vf1="$f1" '/Pointer/{print f1;print;next}1' file2

(または、「ポインター」の後にFile1を挿入する場合)

awk -vf1="$f1" '/Pointer/{print;print f1;next}1' file2

2

私の好ましい方法:テンプレート化

sed 's/CHANGEME/$x/g' origfile | x="$(<file2insert)" envsubst '$x' > newfile

これにより、origfileで発生するすべてのCHANGEMEfile2insertのコンテンツに置き換えられます。最初のCHANGEMEのみを置換するために、sedから最後のgを削除します。


$x2番目のコマンドでのみ定義されている場合、最初のコマンドでどのように使用できますか?
トーター

最初のコマンドの「$ x」は、2番目のコマンドのenvsubstによって評価されるプレースホルダーにすぎません。sedスクリプトの単一引用符では、$ xはシェルによって評価されません。
nrc

2

[ファイルの内容を別のファイルに挿入してからパターンを挿入する]

sed -i '/PATTERN/r file1' -e //N file2

[パターン後]

sed -i '/PATTERN/r file1' file2

Nうまく動作しますが、パターンは入力の最後の行と一致しない場合
Sundeep

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.