大容量ASCIIテキストファイルで検索/置換機能を実行する必要があります。入力ファイルからの短い抜粋:
gene_id "MSTRG.1";
gene_id "MSTRG.1";
gene_id "MSTRG.2";
gene_id "MSTRG.3";
このMSTRG
文字列は、テンプレートファイル内の他のIDに置き換えられます。
MSTRG.1 AT1G01030
MSTRG.2 AT1G01010
MSTRG.3 AT1G01035
単純なwhileループは、テンプレートの各行を繰り返して置き換えます。
while read bef aft
do
echo "Searching for $bef"
echo "Replacing with $aft"
sed "s/$bef/$aft/g" input > output
done < template
MSTRG.2
その後、アイテムは正しく置き換えられますが変更されていませんMSTRG.1
。出力は次のとおりです。
gene_id "MSTRG.1";
gene_id "MSTRG.1";
gene_id "AT1G01010";
gene_id "AT1G01035";
修正する
これが私がしたことです。
while read bef aft
do
sed -i "s/$bef/$aft/g" input
done < template
答え1
問題は、ループを繰り返すたびに出力ファイルを削除して最新の変更のみを残し、output
以前の変更は残らないことです。
代わりに、template
ファイルを一連のsed
コマンドに簡単に変換できます。
$ awk '{ printf("s/%s/%s/g\n", $1, $2) }' template
s/MSTRG.1/AT1G01030/g
s/MSTRG.2/AT1G01010/g
s/MSTRG.3/AT1G01035/g
...その後、ファイルに適用します。
$ awk '{ printf("s/%s/%s/g\n", $1, $2) }' template | sed -f - input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";
一部の実装では、標準入力の意味をsed
認識しません。-
このタイプのこの方法を使用するには、にsed
置き換えます。-f -
-f /dev/stdin
または、以下からすべての操作を実行できますawk
。
$ awk 'FNR == NR { pat[$1] = $2; next } { for (p in pat) gsub(p, pat[p]); print }' template input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";
上記のすべてのバリアントは、最初の列の内容を次のtemplate
ように使用します。正規表現、意味.
(点)が一致どの特徴。
答え2
各ループ反復で出力ファイルを上書きするのではなく、入力ファイルを出力ファイルにコピーしてこの出力ファイルで作業できます。
sed
オプションの変更は-i
同じファイルに書き込まれるため、以前の代替エントリは失われません。
cp input output
while read bef aft
do
echo "Searching for $bef"
echo "Replacing with $aft"
sed -i "s/$bef/$aft/g" output
done < template
答え3
#!/usr/bin/perl -i
use strict;
# The %re hash holds the regexp searches and replacement strings.
my %re = ();
my $tfile = shift;
open(TEMPLATE, "<", $tfile) || die "couldn't open $tfile for read: $!\n";
while(<TEMPLATE>) {
chomp;
my ($search,$replace) = split;
$re{qr/$search/} = $replace;
};
close(TEMPLATE);
while (<>) {
foreach my $s (keys %re) {
s/$s/$re{$s}/g;
};
print;
}
これはtemplate
、ファイルを読み取り、%re
正規表現の検索と置換という連想配列(別名「ハッシュ」)を構築します。
次に、コマンドライン(たとえばinput
)に残っている各ファイル名を繰り返し、各入力行で検索と置換の両方を実行します。正規表現をプリコンパイルするために使用されますqr//
。行が多いと、これはマイナーな最適化にすぎませんが、行が多いとtemplate
速度が大幅に向上する可能性があります。
この-i
行#!/usr/bin/perl -i
は、変更を標準出力に印刷するのではなく、Perlに入力ファイルの内部編集を実行させます。たとえば、-i.bak
ファイルが変更される前にファイルのバックアップコピーをアーカイブするには、に変更します。
たとえば、別の名前で保存してcryptic0.pl
実行可能にし、chmod +x cryptic0.pl
次のように実行します。
$ ./cryptic0.pl template input
スクリプトは端末に出力を生成しません。代わりに入力ファイルを編集します。
たとえば、input
ファイルは次のように変更されます。
$ cat input
gene_id "AT1G01030";
gene_id "AT1G01030";
gene_id "AT1G01010";
gene_id "AT1G01035";
ちなみに、このスクリプトはすべての行のすべての項目を適切な代替文字列に変更します。確信していれば、ただ持てる一つ指定された行と一致する場合は、次の行を変更して作業を高速化できます。
s/$s/$re{$s}/g;
これに関して:
s/$s/$re{$s}/ && last;
これにより、スクリプトは foreach ループからそのステートメントに移動し、検索print
と置換が成功した直後に次の入力行に移動します。
ところで、参照してくださいシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?テキスト処理にshループを使用するのはなぜ悪い考えですか?または代わりに、または、または他のawk
ものをperl
使用してください。sed
sh
bash