これは私のものですfile1
:
#$BQ #{ボリューム@ホーム} #データベースバー #relationshiptcdeatid #コピー1 #{バージョン0} #opendb #クリア #.ルノ:= 72 #.infno:=1 #.tid.noel := 101 #.tid.info:=64 #.tid.setnr:=1225 <---(1225番号が変更されます) #.typeidm:=1 #.ソーステーブル:= 2 #writedb #クリア #.ルノ:= 72 #.infno:=205 #.tid.noel := 101 #.tid.info:=76 #.tid.setnr:=5625 <---(5625番号が変更されます) #.typeidm:=1 #.ソーステーブル:= 2 #writedb #$EOJ
file2
正しい項目があります。
#.tid.info:=3345 <---(この番号を入力したいと思います。ファイル164の代わりに) #.tid.setnr:=1254 <---(この番号を入力したいと思います。ファイル11225の代わりに) #.tid.info:=5567 <---(この番号を入力したいと思います。ファイル176の代わりに) #.tid.setnr:=9056 <---(この番号を入力したいと思います。ファイル15625の代わりに)
file1
からのデータに基づいて変更したいと思いますfile2
。
頑張りました
sed "s/tid.setnr := 1225/tid.setnr := 1254/g" file1 > modified_file1
しかし、これを手動で実行したくありません。スクリプトで新しい値と値を読み取って変更するようにtid.info
したいとtid.setnr
思いfile2
ますfile1
。file2
には、等が含まれています。file1
tid.info
file2
file1
tid.setnr
答え1
GNU sed R コマンドを使用します。
sed -e 's/^#.tid.setnr :=.*//;tA;b;:A;R file2' -e 'd' file1
答え2
これを行う1つの方法はスクリプトをsed
生成することです。sed
tmpfile=/tmp/Nainita.$$
exec 3< file2
grep -n "tid\.setnr" file1 | while IFS=: read n junk
do
IFS= read -r line <&3 || break
printf "%sc%s\n%s\n" "$n" '\' "$line"
done > "$tmpfile"
exec 3<&-
sed -f "$tmpfile" file1 > modified_file1
rm -f "$tmpfile"
exec 3< file2
file2
ファイル記述子を読むために開きます。 3.- 行番号で次の行を探します
grep -n
。これはループに供給されます。file1
tid.setnr
while
while IFS=: read n junk
while … read …
一度に1行ずつ読み取ることを意味し、読み取る情報がある限り繰り返します(つまり、データの終わりに達すると停止)。IFS=: read n junk
:
最初の行(つまり元の行番号)の前のgrep -n
すべての項目を読み取り、残りのn
行(前のデータ行)tid.setnr
を読み取ることを意味しますjunk
。これは気にしないので無視します。
IFS= read -r line <&3
ファイル記述子3()から1行を読みfile2
、シェルがそれを破損させないように指示する方法をすべて実行し、名前付き変数に入れますline
。… || break
上記の操作がread
失敗した場合(おそらくファイルの終わりのため)、ループを中止してください。printf
書いたsed
氏hangeコマンドは行番号を指し、これはその行を変数の内容n
で置き換える必要があることを示します。line
done > "$tmpfile"
ループの終わりを示しwhile
、ループ全体の標準出力があることを指定します$tmpfile
。結果は次のとおりです。13c\ #.tid.setnr:=1254 22時\ #.tid.setnr:=9056
while
両方の入力のいずれかからEOFを取得すると、ループは終了します。したがって、行よりも多くの行がある場合、file1
追加の行は変更されていません(つまり、対応するコマンドは生成されません)。同様に、より多くの行がある場合、追加の行は無視されます。残念ながら、この機能を追加することは難しくありませんが、この違いは報告されません。tid.setnr
file2
c
file2
tid.setnr
file1
exec 3<&-
ファイル記述子を閉じます 3.sed -f "$tmpfile" file1 > modified_file1
sed
で実行しfile1
、からコマンドを読み取り、$tmpfile
出力を書き込みますmodified_file1
。
必要に応じて動作する必要があります。もちろん、必要に応じてファイル名を変更できます。 「現状のまま」一度実行し、ファイルを見てmodified_file1
(または出力をリダイレクトしないようにコマンドを変更してsed
画面に書き込む)、出力が必要なものであることを確認する必要があります。その後、必要に応じてその場所で編集sed
するようにコマンドを変更できます。sed -i
file1
sed
コマンドで「行番号が多すぎます」などのエラーが発生した場合は、$tmpfile
スクリプトファイル()をより小さなファイルに分割してみてください。各コマンドは2行なので、100個未満のコマンドサイズから始めることをお勧めします。たとえば、90のコマンドまたは180の行です。テキストエディタ1を使用してこれを手動で実行できますが、この作業用に特別に作成されたツールがあります。直感的にsplit
.commandと呼ばれます。
split --lines=180 "$tmpfile"
xaa
スクリプトは現在のディレクトリで、、、、xab
...というxac
ファイルに分割されます。最初N−1の長さは180行です。最後の項目は、全体を構成するために必要なすべての項目です(≤180)。たとえば、500個のインスタンスがある場合、スクリプトの長tid.setnr
さは1000行になり、6個のx
ファイル(
xaa
、、、、)はそれぞれ180行で構成され、100行になります。今やるxab
xac
xad
xae
xaf
sed -f xaa file1 > modified_file1aa
それでも「行が多すぎます」というメッセージが表示されたら、戻って行数を減らしてもう一度やり直してください--lines
。エラーが報告されない場合は、modified_file1aa
最初の90行がtid.setnr
変更されていることを確認してください。よさそうだと思います。
sed -f xab modified_file1aa > modified_file1ab
sed -f xac modified_file1ab > modified_file1ac
sed -f xad modified_file1ac > modified_file1ad
sed -f xae modified_file1ad > modified_file1ae
sed -f xaf modified_file1ae > modified_file1af
modified_file1af
今最後ですmodified_file1
。
実験したい場合は、次のことができます。
--lines
最大値が何であるかが見つかるまで、より大きな数字を試してください。努力する
sed -f xaa -f xab -f xac -f xad -f xae -f xaf file1 > modified_file1_test
しかし、これはうまくいかないかもしれません。
- 上記の実験を行ったら、結果を教えてください。
これを一度だけ行うと完了です。ただし、これを繰り返し実行する必要がある場合は、この回答の上部にあるコードブロックの最後の2行を次に変更してください。
分割 --lines=180 "$tmpfile" <---(もちろん自分に合った数字を使用してください) cp file1 変更されたファイル 1 fの場合x * する sed -i -f "$f" 変更された_file1 完璧 rm -f "$tmpfile" x*
前述のように、この-i
オプションはsed
指定されたファイルをその場所で編集するように指示します(つまり、変更を入力ファイルに書き戻します)。またはより簡単に、
split --lines=180 "$tmpfile"
for f in x*
do
sed -i -f "$f" file1
done
rm -f "$tmpfile" x*
原稿をそのまま維持する必要がない場合file1
。
使用法の概要は次のとおりですsplit
。
分けられる[オプション]… … [入力する[プレフィックス]]
デフォルトの動作はPREFIXaa
、等という名前のファイルを生成することですPREFIXab
。PREFIXac
つまり、デフォルトPREFIX
はいx
。名前で始まる別のファイルがある場合は、唯一のファイル(または)で定義し、上記のx
内容を次のように変更する必要があります。prefix
prefix=Nainita.$$.
prefix=/tmp/Nainita.$$.
split --lines=180 "$tmpfile" "$prefix"
for f in "$prefix"*
do
sed -i -f "$f" file1
done
rm -f "$tmpfile" "$prefix"*
______
1罰が好きなら、できるそうしてくださいsed
- しかし、なぜ不気味なのですか?
答え3
{ sed '/^#\.tid\.setnr/!d;=;g;G' |
paste -d'c\\\n' - - - ./addfile
} <./mainfile | sed -f - ./mainfile
関連行番号の前にのみ追加されます。./メインファイル各行に。 /ファイルを追加コマンド文字列c\
と<改行>編集のために結果をsed
別のスクリプトにスクリプトに渡す前に./メインファイル。サンプルデータに基づいて生成されたスクリプトは次のとおりです。
13c\
#.tid.setnr := 1254 <--- (I want to put this number in file1 in place of 1225)
22c\
#.tid.setnr := 9056 <--- (I want to put this number in file1 in place of 5625)
...sed
ぶら下がっているc
線を表します。13そして22各コマンドに一致する追加行を出力します。
答え4
パールを見つけました。このスクリプトは、トリックを実行しているように見えるおおよそのスクリプトです。
#!/usr/bin/perl
#
use strict;
# subroutine to load a test file into an array
sub load{
my $file = shift;
open my $in, "<", $file or die "unable to open $file : $!";
my @data = <$in>;
chomp @data;
foreach (@data) { s/\cM//g;}
return @data;
}
my $file1 = shift || die "usage: $0 [file1] [file2]\n";
my @file1_data = &load($file1);
my $file2 = shift || die "usage: $0 [file1] [file2]\n";
my @file2_data = &load($file2);
my $i = 0;
foreach( @file1_data )
{
if( $i < @file2_data )
{
my @s = split / /, $file2_data[$i];
if( @s )
{
if( /^$s[0]/ )
{
$_ = $file2_data[$i++];
}
}
}
print "$_\n";