ファイルを文字ごとに分割してデータに追加します。

ファイルを文字ごとに分割してデータに追加します。

ファイルの2番目のフィールドをアンダースコア(スペースで区切って)に分割し、2番目の部分をデータに新しいフィールド(タブとして出力)として追加する方法を簡単にしたいという質問があります。

例えば file.txt

2 1_123
2 2_345

out.tab:

2 1_123 123
2 2_345 345

すでに使用できますが、より簡単な方法はありますか?複雑すぎるようです...

paste -d' ' file.txt <(cat file.txt | cut -d'_' -f 2- ) | tr [:blank:] \\t > out.temp && mv out.temp out.tab

答え1

すべての変換はファイル内の同じ行内でデータを混在させるため、sedやawkなどのデータを1行ずつ操作するツールを使用する方がはるかに簡単です。

sed -e 's/^[^ \t]*[ \t][^ \t]*_\([^_ \t]*\)/&\1\t/' -e 'y/ /\t/' <<<'2 1_123'

説明:正規表現を使用して、最初のフィールド(最初のスペースまたはタブまで)、2番目のフィールドから最後のアンダースコアまで、2番目のフィールドを最後のアンダースコア(\(…\)テキストを置き換えるためにグループに入れます)と一致させます。同じテキスト(&置換)を保持し、その後に一致するグループの内容(\1)が続きます。 2番目のフィールド以降のすべてのフィールドは変更されません。最後に、すべてのスペースをタブ文字で置き換えます。

sedがタブ表示をサポートしていない場合は、\t代わりにリテラルタブを使用してください。

答え2

2番目と最後のフィールドに1つの下線のみを表示する簡単な例を表示するには、次のようにします。

$ sed 's/_\(.*\)/& \1/' file | tr ' ' '\t'
2   1_123   123
2   2_345   345

または、sed実装が拡張正規表現をサポートしている場合:

$ sed -E 's/_(.*)/& \1/' file | tr ' ' '\t'
2   1_123   123
2   2_345   345

これは最初の項目_とそれ以降のすべての項目と一致します。角かっこは一致する文字列をキャプチャし、それらを置換の右側に引用することができます\1&一致するすべての項目なので、_2 番目のフィールドの残りの部分がその後に続きます。したがって、置換はそれ自体、スペース、および次の文字を印刷します_trすべてのスペースをタブに置き換えます。


必要な数のフィールドを持つことができ、そのうちの1つを含めることができるより複雑な場合は、次のようにし_ますperl

$ perl -lane 's/ +/\t/g; $F[1]=~/_(\S+)/; print "$_\t$1"' file 
2   1_123   123
2   2_345   345

-aこれにより、perl入力スペースが配列に分割されます@F。 2番目のフィールドは、$F[1]配列が最初から計算されるためです0-n「入力ファイルを1行ずつ読み、-e与えられたスクリプトを適用する」という意味です。-l入力行から末尾の改行を削除し、各呼び出しに改行を追加しますprint

s/ +/\t/g;1つ以上のスペースを含むすべての項目をタブに置き換え、$F[1]=~/_(\S+)/;2番目のフィールドの次の文字_と一致して別の名前で保存し、$1現在print "$_\t$1"の行($_)と一致を印刷します。


フィールドデータに基づいたもう1つの便利なツールは次のとおりですawk

$ awk '{gsub(/ /,"\t");l=$2; sub(/.*_/,"",l); print $0"\t"l}' file 
2   1_123   123
2   2_345   345

では、awk入力行が空白に自動的に分割され、$1m $2...になります$Ngsub(/ */,"\t");すべてのスペースをタブに置き換えます。までの内容をすべて削除し、()行を印刷してから、タブと修正された2番目のフィールドをl=$2印刷します。lsub(/.*_/,"",l);_lprint $0"\t"l$0

答え3

t=$(printf \\t)
sed "s/[^ _]*\(_\([^ _]*\)\)\{0,1\}[^ ]*/& \2/2;s/  */$t/g" <in >out

...2番目のフィールドの数に関係なく、またはフィールド数に関係なく機能する必要があります。ただし、一連のスペースを単一のタブ文字に変換します。 2つの連続したスペースを2つのフィールド区切り文字と見なす必要がある場合は、次のようにします。

y/ /$t/

...代わりにそこに行きます...

s/  */$t/

...置換。

関連情報