コマンドラインからフィールドベースのデータを操作するにはどうすればよいですか?例
- N番目のフィールドが
foo
である行のみを印刷するにはどうすればよいですか。 ? - N番目のフィールドが
foo
ではない行のみを印刷するにはどうすればよいですか。 ? - N番目のフィールドが
foo
と一致する行のみを印刷するにはどうすればよいですか。 ? - フィールドNを
foo
に変更するにはどうすればよいですか。 ?
* nixシステムでフィールドベースのデータを操作するのを容易にする標準的なアプローチまたはツールセットはありますか?
承認された回答:
フィールドを処理するときに使用できる基本的なアプローチは2つあります。i)フィールドを理解するツールを使用する。 ii)正規表現を使用します。 2つのうち、前者は通常、より堅牢でシンプルです。
* nixで一般的に利用可能なツールの多くは、フィールドを処理するように明示的に設計されているか、フィールドを容易にするための巧妙なトリックを備えています。
1。フィールドを理解するツールを使用する
1.1 awk
ここでの古典的なツールはawk
です 。各入力行が自動的にフィールドに分割されます(フィールド区切り文字はデフォルトでは空白ですが、 -F
を使用して変更できます。 フラグ)、フィールドは awk
で使用できます $ nとしてのスクリプト
ここで、 n
フィールド番号です。最初のフィールドは$1
です 、2番目の $ 2
など
-
3番目のフィールドが
foo
である行を印刷します 。awk '$3=="foo"' file
区切り文字を
:
に変更しますawk -F":" '$3=="foo"' file
awk
のデフォルトのアクション 印刷することです。したがって、上記のコマンドは、3番目のフィールドがfoo
であるすべての行を出力します。 。-F
を使用する場合 、任意のフィールドセパレータを設定でき、正規表現を使用することもできます。 -
3番目のフィールドが
foo
ではない行のみを印刷するにはどうすればよいですか。 ?awk '$3!="foo"' file
-
3番目のフィールドが
foo
と一致する行のみを印刷するにはどうすればよいですか。 ?パターンに一致するフィールドを探しているだけの場合(たとえば、
foo
foobar
に一致します )、〜
を使用します==
の代わりに :awk '$3~/foo/' file
-
3番目のフィールドが
foo
と一致しない行のみを印刷するにはどうすればよいですか。 ?awk '$3!~/foo/' file
-
3番目のフィールドを
foo
に変更するにはどうすればよいですか。 ?awk '$3="foo"' file
1.2 Perl
もう1つの選択肢はperl
です ワンライナー。 awkと同様に、Perlはフル機能のスクリプト言語ですが、スクリプトを入力として受け取るコマンドラインプログラムとして実行することもできます。その動作はコマンドラインスイッチによって変更されます。この質問に最も関連するのは次のとおりです。
-
-e
:perl
のスクリプト 実行する必要があります; -
-n
:入力ファイルを1行ずつ読み取ります; -
-p
:-e
で指定されたスクリプトを適用した後、各入力行を出力します; -
-l </ code> :各入力行から末尾の改行を削除し、各
print
に改行を追加します 電話; -
-a
:awk-mode、各入力行を配列@F
に分割します; -
-F
:-a
のフィールドセパレータ 。
awk
との重要な違い そのperl
の-a
スイッチはファイルを配列に分割します。 Perlでは、配列は1ではなく0から始まります。これは、2番目のフィールドが実際には $ F [1]
であることを意味します。 $ F [2]
ではありません 。これらすべてを念頭に置いて、 perl
上記に相当するものは次のとおりです。
-
3番目のフィールドが
foo
である行を印刷します 。perl -ane 'print if $F[2] eq "foo"' file
区切り文字を
:
に変更しますperl -F":" -ane 'print if $F[2] eq "foo"' file
awk
とは異なり 、perl
フィールド区切り文字として正規表現を使用することはできません。特定の文字または文字列である必要があります。 -
3番目のフィールドが
foo
ではない行のみを印刷するにはどうすればよいですか。 ?perl -ane 'print unless $F[2] eq "foo"' file
-
3番目のフィールドが
foo
と一致する行のみを印刷するにはどうすればよいですか。 ?perl -ane 'print if $F[2]=~/foo/' file
-
3番目のフィールドが
foo
と一致しない行のみを印刷するにはどうすればよいですか。 ?perl -lane 'print unless $F[2]=~/foo/' file
-
3番目のフィールドを
foo
に変更するにはどうすればよいですか。 ?これはPerlではもう少し面倒です。通常のアプローチは、
@F
の値を変更することです。 配列してから、配列を出力します。スペースで区切られた単純なファイルを使用すると、これは簡単です。perl -lane '$F[2]="foo"; print "@F"' file
別の区切り文字を使用すると、
join
する必要があります アレイ。それ以外の場合は、スペースで区切られて印刷されます:perl -F: -lane '$F[2]="foo"; print join ":",@F' file
2。正規表現を使用する
ここでの考え方は、行内のターゲット文字列の位置を定義する正規表現(略して「regex」)を使用することです。たとえば、フィールドが:
で区切られているファイルの場合 、1番目の:
までのすべてを照合することで、2番目のフィールドを見つけることができます。 (最初のフィールド)次に2番目のフィールドを探します:
^[^:]*:[^:]*:
この正規表現の意味:
-
^
:行の先頭; -
[^]
:否定された文字クラス。[^:]
「以外のもの:
」を意味します 「; -
*
:前のパターンの0以上; -
:コード> :リテラル
:
;
まとめると、これは最初の [^:] *
を意味します は最初のフィールドで、2番目は2番目のフィールドです。明らかに、これは14番目のフィールドを探している場合はあまり実用的ではありませんが、より単純なものには役立ちます。では、これをどのように実装してデータを操作するのでしょうか。これを行うことができるさまざまなツールがあります。これらの例では、 sed
を使用します ただし、 awk
でも非常によく似たことができます。 、 perl
またはpython
。
-
2番目のフィールドが
foo
である行のみを印刷するにはどうすればよいですか。 ?sed -n '/^[^:]*:foo:/p' file
-n
通常の出力と/regex / p
を抑制します 「正規表現が一致したすべての行を印刷する」という意味です。 -
2番目のフィールドが
foo
ではない行のみを印刷するにはどうすればよいですか。 ?sed '/^[^:]*:foo:/d' file
上記の論理的な逆。ここでは、
/ regex / d
「正規表現が一致する行をすべて削除する」という意味です。 -
2番目のフィールドが
foo
と一致する行のみを印刷するにはどうすればよいですか。 ?sed -n '/^[^:]*:[^:]*foo/p' file
-
2番目のフィールドが
foo
と一致しない行のみを印刷するにはどうすればよいですか。 ?sed '/^[^:]*:[^:]*foo/d' file
-
2番目のフィールドを
foo
に変更するにはどうすればよいですか。 ?sed 's/([^:]*:)[^:]*/1foo/' file
または、
sed
以降 置換は、単純な数値フラグを使用して繰り返すことにより、パターンの発生に直接対処できます。sed 's/[^:]*/foo/2' file