155

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

列1列2
str1 1
str2 2
str3 3

列を再配置したい。以下のコマンドを試してみました

カット-f2,1file.txt

このコマンドは列を並べ替えません。なぜそれが機能しないのか考えていますか?

4

9 に答える 9

175

cut(1)マニュアルページの場合:

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

最初にフィールド1に到達するため、フィールド2が印刷されます。

awk代わりに使用してください:

awk '{ print $2 " " $1}' file.txt
于 2010-01-24T22:21:35.537 に答える
69

組み合わせcutpaste

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

コメント経由:次の手順を実行することで、バシズムを回避し、カットの1つのインスタンスを削除することができます。

paste file.txt file.txt | cut -f2,3
于 2013-02-19T15:52:51.397 に答える
7

シェルだけを使用して、

while read -r col1 col2
do
  echo $col2 $col1
done <"file"
于 2010-01-25T00:19:30.820 に答える
7

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

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

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

于 2014-04-07T17:07:32.243 に答える
6

使用join

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

ノート:

  • -t $'\t'GNU では、失敗することなくjoinより直感的になります(coreutils v8.28以前?)。おそらく、次のような回避策が必要になるバグです。参照:unix結合区切り文字char-t '\t' $ $

  • 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
    
于 2018-11-18T20:29:28.430 に答える
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

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

于 2013-10-10T09:49:32.923 に答える
2

列を複製してから実行することを提案する回答への追加と同じようにcut。複製pasteなどの場合、ファイルに対してのみ機能し、ストリームに対しては機能しません。その場合は、sed代わりに使用してください。

cat file.txt | sed s/'.*'/'&\t&'/ | cut -f2,3

これはファイルとストリームの両方で機能します。これは、を使用してファイルから読み取るのではなく、列を再配置する前にcat何か面白いことをした場合に興味深いものです。

比較すると、以下は機能しません。

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

ここで、double stdinプレースホルダーpasteはstdinを複製しませんが、次の行を読み取ります。

于 2021-01-04T11:00:53.967 に答える
1

sedを使用する

sedを基本的な正規表現のネストされた部分式とともに使用して、列の内容をキャプチャして並べ替えます。このアプローチは、この場合のように、列を並べ替えるカットの数が限られている場合に最適です。

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

例えば:

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

収量:

bar foo

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

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

崩壊するスペース

最も単純な使用法を説明するために、複数のスペースを1つのスペースに折りたたむことができ、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は列に一致する式です。

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

于 2020-01-22T03:18:49.723 に答える
0

@Metからの回答を拡張し、Perlも使用し
ます。入力と出力がTABで区切られている場合:

perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file

入力と出力が空白で区切られている場合:

perl -lane 'print join " ", @F[1, 0]' in_file

ここで
-eは、Perlに、個別のスクリプトファイルではなく、インラインでコードを検索するように指示
-nし、一度に1行ずつ入力を読み取り、その行を読み取った後に(* NIX上の)
-l入力レコードセパレーターを削除し、出力を追加します。レコード区切り文字(* NIX上)をそれぞれに、空白の入力行を配列に分割し、空白の代わりにTABの入力行を配列に分割します。\nchomp\nprint
-a@F
-F'\t'-a@F

@F[1, 0]は、配列の2番目と1番目の要素で構成される配列@Fです。Perlの配列はゼロインデックスであり、のフィールドcutは1インデックスであることに注意してください。したがって、のフィールド@F[0, 1]はのフィールドと同じcut -f1,2です。

このような表記により、上記に投稿された他のいくつかの回答よりも柔軟な入力操作が可能になることに注意してください(単純なタスクには問題ありません)。例えば:

# reverses the order of fields:
perl -F'\t' -lane 'print join "\t", reverse @F' in_file

# prints last and first fields only:
perl -F'\t' -lane 'print join "\t", @F[-1, 0]' in_file
于 2020-07-31T20:40:36.960 に答える