行番号を事前に知って別のファイルに保存します。
cat linenos
2
15
42
44
... etc
ご覧のとおり、行が隣接していないため、rangeは使用できませんsed
。目標は、ターゲットファイルの行を変更することです。たとえば、ターゲットファイル行の前にMARKERなどのマーカーを追加します。
sed
簡単なアプローチは、各行を変更するために複数回呼び出すことです。
for l in $(cat linenos)
do
sed -i "${l}s/^/MARKER/" target_file
done
これは明らかにsedを何度も呼び出すでしょう。
警告する:*このアプローチは非効率的であるだけでなく、そのようなマークアップを挿入しない修正がある場合にも問題が発生する可能性があります。 sedコマンド(darなど)で行を削除または挿入すると、ループ内の次のsed実行のためにlinenosの最初の行番号が無効になります。
改善/最適化をどのように提案しますか?
例 linenos ファイル
cat linenos
2
5
サンプルオブジェクトファイル
cat target_file
line one
line two
line three
line four
line five
line six
修正されたtarget_fileの期待される結果
cat target_file
line one
MARKERline two
line three
line four
MARKERline five
line six
私が考えた可能な方法は、sedシーンを動的に生成することです。
SEDCMD=$(for l in $(cat linenos); do echo -n "${l}s/^/MARK/;" ; done)
sed -i -e "$SEDCMD" targetfile
@スチールドライバ次のような方法はアイデアと同じですが、よりエレガントで簡潔です。
答え1
sed自体(または他の選択したテキスト処理ユーティリティ)を使用して行番号をsed式に変換し、スイッチを使用して-f
sedに渡すことができます。
前任者。
sed 's:$:s/^/MARKER/:' linenos | sed -f- -i target_file
これは少なくともsedのみを呼び出します。二重。
答え2
perl
(GNUソースsed
)を使う-i
:
perl -pi -e '
BEGIN{$l{0+$_}=1 while <STDIN>}
$_ = "MARKER$_" if $l{$.}' target_file < linenos
perl
私たちはstdinに行番号のリストを提供します。これはBEGIN
塊として読み込まれます。
各入力行にを使用して、行を数値に変換します0+$_
。これにより、改行文字が消え、数字が正規化されます(1e0、1、01がすべて1になります)。
ハッシュテーブルは各行番号の値をキーで%l
埋めます。1
target_file
現在行番号()がゼロ以外の値である行の前に追加されるメインループ-p
で処理されます。MARKERS
$.
%l
答え3
$ awk 'NR==FNR{a[$1]="MARKER"; next} {print a[FNR] $0}' linenos target_file
line one
MARKERline two
line three
line four
MARKERline five
line six
または少しメモリを節約します。
$ awk 'NR==FNR{a[$1]; next} {print (FNR in a ? "MARKER" : "") $0}' linenos target_file
line one
MARKERline two
line three
line four
MARKERline five
line six
「内部」編集(perlおよびGNU sedと同じ-i
)が必要な場合は、GNU awkを使用してawk '...'
文の前にaを追加してawk -i inplace '...'
ファイルを空にしないようにしてください。 IMHO awk(または他のUNIXツール)を使用してこれを行う方が簡単です。print;
next
linenos
awk 'script' linenos target_file > tmp && mv tmp target_file
答え4
別のアプローチは、適切な場所で修正するed
代わりに使用されます。sed
target_file
(while IFS= read n; do echo "${n}s/^/MARKER/"; done < linenos; echo w) | ed -s target_file