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"
つまり、「ポインタ」を含む行の前のFile1
にFile2
の内容を貼り付けます。
sed
にはそのための関数があり、インラインで変更を行うことができます。
sed -i -e '/Pointer/r file1' file2
しかし、これはあなたのPointer行をfile1の上に置きます。下に置くには、ライン出力を遅延させます。
sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2
GNU sed
sed '/Pointer/e cat file1' file2
manual に従ってe [command]
Rコマンドとは異なり、コマンドの出力はすぐに出力されることに注意してください。代わりに、rコマンドは現在のサイクルの終わりまで出力を遅延させます。
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
これには、ファイルに3回アクセスするという欠点がありますfile2
ですが、sed
of awk
ソリューションよりも明確な場合があります。
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
ed
の簡単な仕事:
ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN
-r file1
は、指定されたファイルをアドレス指定された行の後(この場合はPointer
に一致する最初の行の前の行)に読み取ります。したがって、これは、Pointer
が複数行で発生した場合でも、file2
のコンテンツを1回だけ挿入します。一致する各行の前に挿入する場合は、g
lobalフラグを追加します。
ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN
ファイルをインプレースで編集する場合は、,p
をw
に置き換えます。
受け入れられた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
コンテンツが挿入されます。最初の一致する行の前にのみ挿入するには、l
oopを使用して、ファイルの終わりに到達するまでn
ext行をプルします。
sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)
これらのsed
ソリューションを使用すると、インプレースで編集できなくなります(ただし、別のファイルにリダイレクトできます)。
ループを使用してfile2の行を読み取ります。 Pointer
で始まる行を見つけたら、file1を出力します。これを以下に示します。
#!/bin/bash
while IFS= read -r line
do
if [[ "$line" =~ ^Pointer.*$ ]]
then
cat file1
fi
echo "$line"
done < file2
sed
を使用してこれを行うにはいくつかの方法があります。 1つの方法は、承認された回答で推奨されているように、読み取りを遅らせることです。次のように書くこともできます:
sed -e '$!N;P;/\nPointer/r file1' -e D file2
...ホールドバッファーを使用して他の場所に後読みを実装する代わりに、少し明示的な先読みを使用します。 N
doesがラインサイクルをインクリメントするため、@ don_crisstiが注記する最後の行で同じ問題が発生します。 r
eadコマンドは行番号で適用されます。
あなたはそれを回避することができます:
echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -
すべてのsed
sが-
を標準入力を意味すると解釈するわけではありませんが、多くの場合はそうです。 ( POSIXによるとsed
は、実装者が-
を標準にしたい場合、-
を標準入力にサポートする必要がありますで???)
別の方法は、追加されたコンテンツを順番に処理することです。 schedulesがr
eadと同じ方法で出力する別のコマンドがあり、sed
がそれを適用してr
eadは、スクリプト化された順序で表示されます。ただし、少し複雑です。sed
からa
ppendを使用して、スクリプト内の別の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
の最初の一致でのみ機能し、その後q
uits入力で機能します。その仕事は...
s/[]^$&\./*[]/\\&/g;H
sed
は、文字を正しく読み取るために文字どおりに読み取るすべてのビットを解釈する必要があるため、すべてのパターン文字が安全にバックスラッシュエスケープされていることを確認してください。それが終わったら、コピーをH
oldスペースに置きます。s|.*|/&/!p;//!d|p; x
sed
からp
rintにすべての入力行!
を伝えますが、/&/
はパターンセーフです。 d
eleteにすべて同じ。 p
rint 2番目のコマンドでsed
を実行し、次にe x
change h
oldとパターンバッファーを保存したコピーで機能するようにします。s|.|r file1&a\\&|p;q
\n
ewlineです。これは、前の行をsed
eldするとH
が前に付加されるためです。したがって、コマンドr file1
を挿入し、その後に\n
ewlineを続け、次にコマンドa\\
for a
ppendの後に\n
ewlineを続けます。残りのH
eld行はすべて、最後の\n
ewlineに従います。最初のスクリプトは次のようになります。
/Pointer-file2 "23"/!p;//!d
r file1
a\
Pointer-file2 "23"
基本的に、2番目のsed
はすべての行を出力しますが、最初のsed
はa
ppendに設定します。その特定の行のtwo標準出力への遅延書き込みはscheduled- 1つ目はfile1
のr
eadで、2つ目はその後に必要な行のコピーです。この場合、最初のsed
の修正は不要です(参照?バックスラッシュなし)。ただし、パターンマッチが入力として再利用されるときはいつでも、ここで私が行う方法.
とにかく、...いくつかの方法があります。
[ファイルの内容を別のファイルのBEFOREパターンに挿入]
sed -i '/PATTERN/r file1' -e //N file2
【パターン後】
sed -i '/PATTERN/r file1' file2
私の好みの方法:templating。
sed 's/CHANGEME/$x/g' origfile | x="$(<file2insert)" envsubst '$x' > newfile
[〜#〜] changeme [〜#〜]origfileで発生するすべての内容をfile2insertの内容に置き換えます。最後のgをsedから削除して、最初に出現した[〜#〜] changeme [〜#〜]のみを置き換えます。
これは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
awk '/Pointer/{system("cat File1")}1' File2