カットを使用して列を再配置する


134

次の形式のファイルを持っています

列1列2
str1 1
str2 2
str3 3

列を並べ替えたい。以下のコマンドを試してみました

cut -f2,1 file.txt

コマンドは列を並べ替えません。なぜ機能しないのか?

ありがとうございました。

回答:


148

以下のためのcut(1)manページ:

-b、-c、-fのいずれか1つのみを使用してください。各リストは、1つの範囲、またはコンマで区切られた多くの範囲で構成されます。選択された入力は、読み取られたのと同じ順序で書き込まれ、正確に1回だけ書き込まれます。

最初にフィールド1に到達するため、それが出力され、次にフィールド2が出力されます。

awk代わりに使用:

awk '{ print $2 " " $1}' file.txt

12
残念ながら、cutこの直感的な並べ替えコマンドはサポートされていません。とにかく、もう一つのヒント:あなたが使用することができるawk-FS-OFS(のようなカスタム入力および出力フィールドセパレータに使用するオプションを-dして--output-delimiterためにcut)。
マラナ2011

12
申し訳ありませんFSが、オプションでOFSあり、変数です。例awk -v OFS=";" -F"\t" '{print $2,$1}'
マラナ2011

2
Git BashのWindowsユーザーへの注意:上記のコマンドからの出力が奇妙で、列が互いに上書きしているように見える場合は、キャリッジリターンが原因です。ファイルのEOLをCRLFからLFに変更します。
jakub.g 2015

1
または、入力ファイルを変更したくない場合は、パイプする| sed 's/\r//' | 前にパイプすることができますawk
jakub.g

2
この1は非常にシンプルですが、単純にタブでの並べ替えのために、\トンとスペースを置き換えるいくつかのために役に立つかもしれない、とあなたはより多くの列をしたい場合には、次の例の場合と同様にそれを行うことができますawk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
FatihSarigol

63

また、組み合わせることができるcutpaste

paste <(cut -f2 file.txt) <(cut -f1 file.txt)

コメント経由:バシズムを回避し、カットのインスタンスを1つ削除することは可能です:

paste file.txt file.txt | cut -f2,3

3
これが「賢い」と見なされるかどうかはわかりませんが、f = file.txt paste <(cut -f2 $ f)<(cut -f1 $ f)です。また、多くの列があり、それらの大きなブロックを移動する場合は、この方法が最も簡単です。
Michael Rusch 2016年

同じ列にある可変長のセルでは機能しません
クレイマー

2
@kraymerどういう意味ですか? cut一意の長さの列セパレーターがある限り、可変長の列でも問題なく機能します。
tripleee 2017年

1
冗長なファイルを排除するには、おそらくティーを使用することができます:
JJW5432

2
それは回避することが可能ですbashISMSをし、1つのインスタンスを削除cut:実行して paste file.txt file.txt | cut -f2,3
AGC

7

シェルだけを使用して、

while read -r col1 col2
do
  echo $col2 $col1
done <"file"

これは非常に非効率的です。通常、たとえば、対応するAwkスクリプトの方がはるかに高速です。また、値を引用するように注意する必要があります"$col2""$col1"-シェルのメタ文字またはデータの他のペテンがある可能性があります。
tripleee 2017年

7

そのためにPerlを使用できます。

perl -ane 'print "$F[1] $F[0]\n"' < file.txt
  • -eオプションは、その後にコマンドを実行することを意味します
  • -nは行ごとに読み取ることを意味します(ファイルを開きます。この場合はSTDOUTで、行をループします)。
  • -aは、そのような行を@F(「F」-フィールドのような)と呼ばれるベクトルに分割することを意味します。Perlは、1から始まるフィールドにインデックスを付けるcutとは異なり、0から始まるベクトルにインデックスを付けます。
  • -F pattern(-Fとpatternの間にスペースなし)を追加して、デフォルトの空白の代わりにファイルを読み取るときに、パターンをフィールド区切りとして使用できます。

perlを実行する利点は、(Perlを知っている場合)列を再配置するよりもFではるかに多くの計算を実行できることです。


perlrun(1)は、-aが暗黙的に-nを設定することを主張していますが、-nを設定せずに実行すると、ループしないようです。奇数。
トレントン

どのバージョン?私とperl -ae print同じようcatに動作します
pwes 2017年

5

使用join

join -t $'\t' -o 1.2,1.1 file.txt file.txt

ノート:

  • -t $'\t'ではGNU joinより直感的な-t '\t' なし$(、失敗のcoreutils v8.28およびそれ以前?)。おそらくバグのような回避策$が必要です。参照:unix join separator char

  • join作業中のファイルが1つしかない場合でも、2つのファイル名が必要です。同じ名前を2回使用するとjoin、目的のアクションが実行されます。

  • リソースが少ないシステムでjoinは、他の回答で使用されている一部のツールよりもフットプリントが小さくなります。

    wc -c $(realpath `which cut join sed awk perl`) | head -n -1
      43224 /usr/bin/cut
      47320 /usr/bin/join
     109840 /bin/sed
     658072 /usr/bin/gawk
    2093624 /usr/bin/perl

3

非常によく似たものに取り組んでいるだけで、私は専門家ではありませんが、使用したコマンドを共有したいと思いました。私はマルチカラムcsvを持っていましたが、必要なのは4カラムだけであり、それらを並べ替える必要がありました。

ファイルはパイプ '|'でした 区切られていますが、それは交換できます。

LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv

確かにそれは本当にラフで準備ができていますが、それに合わせて調整することができます!


これは提起された質問には答えません。スタックオーバーフローの精神で、投稿する前に問題に答える時間を確保してください。
ビルゲイル

0

sedの使用

sedを基本正規表現のネストされたサブ表現とともに使用して、列のコンテンツをキャプチャして並べ替えます。この方法は、この場合のように、列を並べ替えるカットの数が限られている場合に最適です。

基本的な考え方は、検索パターンの興味深い部分を\(and \)で囲むことです。これは、置換パターンで再生できます\##は検索パターン内の部分式の連続した位置を表します。

例えば:

$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"

収量:

bar foo

部分式の外のテキストはスキャンされますが、置換文字列での再生のために保持されません。

質問では固定幅の列については説明しませんでしたが、これは提案されたソリューションの価値ある尺度であるため、ここで説明します。簡単にするために、ファイルがスペースで区切られていると仮定しましょう。ただし、ソリューションは他の区切り文字にも拡張できます。

折りたたみスペース

最も簡単な使用法を説明するために、複数のスペースを単一のスペースに折りたたむことができ、2番目の列の値がEOLで終了している(スペースが埋め込まれていない)と仮定します。

ファイル:

bash-3.2$ cat f
Column1    Column2
str1       1
str2       2
str3       3
bash-3.2$ od -a f
0000000    C   o   l   u   m   n   1  sp  sp  sp  sp   C   o   l   u   m
0000020    n   2  nl   s   t   r   1  sp  sp  sp  sp  sp  sp  sp   1  nl
0000040    s   t   r   2  sp  sp  sp  sp  sp  sp  sp   2  nl   s   t   r
0000060    3  sp  sp  sp  sp  sp  sp  sp   3  nl 
0000072

変換:

bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  nl
0000020    1  sp   s   t   r   1  nl   2  sp   s   t   r   2  nl   3  sp
0000040    s   t   r   3  nl
0000045

列幅を維持する

次に、幅が一定の列を含むファイルにメソッドを拡張し、列の幅を変更できるようにします。

ファイル:

bash-3.2$ cat f2
Column1    Column2
str1       1
str2       2
str3       3
bash-3.2$ od -a f2
0000000    C   o   l   u   m   n   1  sp  sp  sp  sp   C   o   l   u   m
0000020    n   2  nl   s   t   r   1  sp  sp  sp  sp  sp  sp  sp   1  sp
0000040   sp  sp  sp  sp  sp  nl   s   t   r   2  sp  sp  sp  sp  sp  sp
0000060   sp   2  sp  sp  sp  sp  sp  sp  nl   s   t   r   3  sp  sp  sp
0000100   sp  sp  sp  sp   3  sp  sp  sp  sp  sp  sp  nl
0000114

変換:

bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1       str1      
2       str2      
3       str3      
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  sp
0000020   sp  sp  nl   1  sp  sp  sp  sp  sp  sp  sp   s   t   r   1  sp
0000040   sp  sp  sp  sp  sp  nl   2  sp  sp  sp  sp  sp  sp  sp   s   t
0000060    r   2  sp  sp  sp  sp  sp  sp  nl   3  sp  sp  sp  sp  sp  sp
0000100   sp   s   t   r   3  sp  sp  sp  sp  sp  sp  nl 
0000114

最後に、質問の例では長さが等しくない文字列はありませんが、このsed式はこのケースをサポートしています。

ファイル:

bash-3.2$ cat f3
Column1    Column2
str1       1      
string2    2      
str3       3      

変換:

bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1   
1       str1      
2       string2   
3       str3    
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000    C   o   l   u   m   n   2  sp   C   o   l   u   m   n   1  sp
0000020   sp  sp  nl   1  sp  sp  sp  sp  sp  sp  sp   s   t   r   1  sp
0000040   sp  sp  sp  sp  sp  nl   2  sp  sp  sp  sp  sp  sp  sp   s   t
0000060    r   i   n   g   2  sp  sp  sp  nl   3  sp  sp  sp  sp  sp  sp
0000100   sp   s   t   r   3  sp  sp  sp  sp  sp  sp  nl 
0000114

シェルの下での他の列並べ替え方法との比較

  • 驚くべきことに、ファイル操作ツールにとって、awkはフィールドからレコードの終わりまで切り取るにはあまり適していません。sedでは、これは正規表現を使用して実行できます。たとえば\(xxx.*$\)xxxは列に一致する式です。

  • シェルスクリプト内に実装する場合、サブシェルの貼り付けと切り取りを使用するのが難しくなります。コマンドラインから機能するコードは、シェルスクリプト内に取り込まれると解析に失敗します。少なくともこれは私の経験でした(このアプローチに私を駆り立てました)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.