以下にサンプルテキストファイル(test_long_sentence.txt)があり、不要なデータを除いてtest1を含むすべての行をgrepしたいと思います。
見積もりが完了する前にどのようにデータを収集できますか?
test_long_sentence.txt
This is some unwanted data blah blah blah
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
This is some unwanted data blah blah blah
20 /test1/theme="Halloween"
注文する:
grep "test1" test_long_sentence.txt
実際の出力:
20 /test1/catergory="food"
20 /test1/target="Adults, \"Goblins\", Elderly,
20 /test1/type="Western"
20 /test1/theme="Halloween"
予想出力:
20 /test1/catergory="food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
PS:私はtest_long_sentence.txtの編集を制御できません。だから私に一行で編集するように頼まないでください。
答え1
awkを使う
$ awk '/test1/{line=$0; while (!(line ~ /[^\\]".*[^\\]"/)) {getline; line=line "\n" $0}; print line}' sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
/test1/
条件です。現在の行に regex と一致する内容が含まれている場合、中かっこで囲まれたtest1
コマンドが実行されます。これらのコマンドは次のとおりです。
line=$0
現在の行の内容は「line」変数に格納されます。
while (!(line ~ !/[^\\]".*[^\\]"/)) {getline; line=line "\n" $0}
現在のコンテンツに
line
エスケープされていない2つの引用符が含まれていない場合は、次の行を取得してviagetline
に追加します。line
line=line "\n" $0
print line
変数には、
line
エスケープされていない2つの引用符が含まれており、それを印刷します。
コマンドを複数行にわたって分散したい場合は、上記と同じコマンドを次のように作成できます。
awk '
/test1/{
line=$0
while (!(line ~ /[^\\]".*[^\\]"/)) {
getline
line=line "\n" $0
}
print line
}' sentence.txt
sedを使う
$ sed -n '/test1/{:a; /[^\\]".*[^\\]"/{p;b}; N; ba}' sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
仕組み:
-n
これは、明示的に要求されない限り、sedが何も印刷しないように指示します。
/test1/{...}
埋め込み行に対して、
test1
次のように中括弧で囲まれたコマンドを実行します。:a
これはラベルを定義します
a
。/[^\\]".*[^\\]"/{p;b}
パターンスペースに現在エスケープされていない2つの引用符が含まれている場合は、パターンスペースを印刷して残りの
p
コマンドをスキップしてb
次の行から始めます。N
ここに到達すると、現在エスケープされていない引用符が2つないことを意味します。パターン空間として次の行を読み込みます。
ba
ラベルに戻り、
a
そのラベルの後にコマンドを繰り返します。
答え2
これはその特定のファイルにawk
代わって適用されます。grep
awk 'NR==3,NR==7;NR==11' test_long_sentence.txt
後でこの問題を解決するには、cat -n
ファイルを実行して含め、除外する行を確認できます。
答え3
これは、入力から連続した行を結ぶ単純なPerlスクリプトです。以下を想定します。
連続した行は単一の空白文字で連結されます。
「行」は、数字と空白で始まる入力行で始まり、次まで続きます。
- 空の画像
- 他の行は数字とスペースで始まります。
空行とその間のすべての行は無視されます(つまり削除されます)。
これは実際の入力ファイルと完全には一致しないかもしれませんが、質問で提供されたサンプル入力と一致します。入力内容に合わせて必要に応じてコードを修正します。
#!/usr/bin/perl
my $skip=1; # start with skip = true.
my $line='';
while(<>) {
chomp;
if (m/^\d+\s+/) { # / this comment is only here to fix SE\'s syntax highlighting
$skip=0;
print $line,"\n" if ($line);
$line = $_;
} elsif (m/^\s*$/) {
if ($line ne '') { print $line, "\n"; $line = ''};
$skip = 1 - $skip;
} elsif (! $skip) {
$line .= " $_";
};
};
たとえば、./join-lines.pl
実行可能ファイルを作成し、chmod +x ./join-lines.pl
次のように実行します。
$ ./join-lines.pl test_long_sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly, Babies, \"Witch\", Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
その後、必要に応じてgrep
他のツールに供給できます。
現在のサンプル入力の場合、すべてのサンプル行に「test1」が含まれているため、出力./join-lines.pl test_long_sentence.txt | grep test1
(可能な一致色を除くgrep
)は上記の出力と同じです。他の一致を見つけるためにより便利にgrepすることができます。たとえば、次のようになります。
$ ./join-lines.pl test_long_sentence.txt | grep Witch
20 /test1/target="Adults, \"Goblins\", Elderly, Babies, \"Witch\", Faries"
まったく同じ入力を再現できるようにする必要がある場合(スペースや不要な行を除く)、行をスペースで連結するのではなく、" ===NL=== "
TABなどの必要な文字や長い文字列(使用しない文字など)を使用してください。入力に表示されます。例えば
} elsif (! $skip) {
$line .= "\t$_";
};
または
} elsif (! $skip) {
$line .= " ===NL=== $_ ";
};
その後、接続文字列を改行文字に変換できますsed
(たとえば、タブを接続文字として使用)。
$ ./join-lines.pl test_long_sentence.txt | grep Witch | sed -e 's/\t/\n/g'
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
より長い文字列を使用して行を連結する別の例:
./join-lines.pl test_long_sentence.txt | grep Witch | sed -e 's/ ===NL=== /\n/g'