awkで最初のフィールドを除くすべてを印刷する


108

次のようなファイルがあります。

AE  United Arab Emirates
AG  Antigua & Barbuda
AN  Netherlands Antilles
AS  American Samoa
BA  Bosnia and Herzegovina
BF  Burkina Faso
BN  Brunei Darussalam

そして、順序を逆にして、最初に$ 1を除くすべてを印刷し、次に$ 1を印刷したいと思います。

United Arab Emirates AE

「フィールド1以外のすべて」のトリックを実行するにはどうすればよいですか?


2
こんにちは@cfisher、それは余分なスペースなしでループangなしで行うことができます。
ファンディエゴゴドイロブレス

回答:


91

割り当ては$1機能しますが、先行スペースが残ります。awk '{first = $1; $1 = ""; print $0, first; }'

また、列の数を見つけてNFループで使用することもできます。


2
完全に怠惰な人のために; これがklashxxのコードです。
Serge Stroobandt、2015年

1
すごい。sedで先頭のスペースを取り除きました: awk {'first = $1; $1=""; print $0'}|sed 's/^ //g'
Thyag

スペースは、通常モードで「Ctrl + V Gd」を押すとVIMで簡単に削除されます
サンティ

107

$1=""ベンジャクソンが言ったようにスペースを残すので、forループを使用します。

awk '{for (i=2; i<=NF; i++) print $i}' filename

したがって、文字列が「one two three」の場合、出力は次のようになります。

2
3

結果を1行にしたい場合は、次のようにします。

awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' filename

これにより、「2つ3つ」が得られます。


4
余分なトレーリングスペース
NeronLeVelu

2
使用方法: awk '{for(i=2;i<=NF;i++){ printf("%s",( (i>2) ? OFS : "" ) $i) } ; print ;}' which:フィールド2をNFに出力し、必要に応じて(つまり、$ 2の前を除いて)出力フィールドセパレーターを追加します。最後の印刷は、最後の改行を追加して、現在の行の印刷を終了します。これは、FS / OFSを変更した場合に機能します(つまり、常に「スペース」であるとは限りません)
Olivier Dulac

2つ目は、私にとって非常にうまくいきました。最初のものは、それほどではありません。理由はよくわかりません。それはテキスト全体をさいの目に切った。

72

オプションを指定してcutコマンドを使用し--complementます。

$ echo a b c | cut -f 1 -d ' '
a
$ echo a b c | cut -f 1,2 -d ' '
a b
$ echo a b c | cut -f 1 -d ' ' --complement
b c

2
awkは重複したスペースを削除し、cutは削除しないため、awkに固有の質問には回答しませんでしたが、これが最も役に立ちました。
Fmstrat 2014年

19
echo a b c | cut -d' ' -f 2- 代替案です
Luis

2
ニース-@LuisソリューションはMacで動作しますが、これは--complementをサポートしていません
metadaddy

21

多分最も簡潔な方法:

$ awk '{$(NF+1)=$1;$1=""}sub(FS,"")' infile
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

説明:

$(NF+1)=$1:「新しい」最後のフィールドのジェネレータ。

$1="":元の最初のフィールドをnullに設定します

sub(FS,""):最初の2つのアクションの後、{$(NF+1)=$1;$1=""}subを使用して最初のフィールド区切り記号を取り除きます。最終的な印刷は暗黙的です。


13
awk '{sub($1 FS,"")}7' YourFile

最初のフィールドとセパレーターを削除し、結果を印刷します(7ゼロ以外の値なので$ 0を印刷します)。


ベストアンサー!賛成。ただ使うのとどう違うの1?このパターンの使い方を知りたいのですが。ありがとう!
Abhijeet Rastogi

10
awk '{ saved = $1; $1 = ""; print substr($0, 2), saved }'

最初のフィールドを設定""葉の単一コピーをOFS開始時に$0。これOFSが単一の文字(デフォルトでは単一のスペース)であると想定すると、で削除できsubstr($0, 2)ます。次に、保存したのコピーを追加します$1


6

Perlソリューションを利用している場合...

perl -lane 'print join " ",@F[1..$#F,0]' file

は、1つのスペースの入力/出力セパレーターを持つ単純なソリューションであり、以下を生成します。

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

次は少し複雑です

perl -F`  ` -lane 'print join "  ",@F[1..$#F,0]' file

また、入力/出力セパレーターは2つのスペースであると想定します。

United Arab Emirates  AE
Antigua & Barbuda  AG
Netherlands Antilles  AN
American Samoa  AS
Bosnia and Herzegovina  BA
Burkina Faso  BF
Brunei Darussalam  BN

次のコマンドラインオプションが使用されます。

  • -n 入力ファイルのすべての行をループし、自動的にすべての行を印刷しない

  • -l 処理前に改行を削除し、後で追加します

  • -a自動分割モード-入力行を@F配列に分割します。デフォルトでは空白で分割する

  • -F autosplit修飾子。この例では、 ''(2つのスペース)で分割されます。

  • -e 次のperlコードを実行します

@F各行の単語の配列、0から始まるインデックス付き
$#Fの単語の数@F
@F[1..$#F]、要素1から最後の要素まで
@F[1..$#F,0]の配列スライス、要素1から最後の要素および要素0までの配列スライス


1
私はそれを実行し、最後に追加の番号があったので、このバージョンを使用しました:perl -lane 'shift @F; print join ""、@F '
Hans Poo

2

gawkのフィールドセパレータは(少なくとも)文字列だけでなく文字(正規表現にすることもできます)にすることができます。データに一貫性がある場合、これは機能します:

awk -F "  " '{print $2,$1}' inputfile

これは、二重引用符の間の2つのスペースです。


現在の状況に対する最良の回答ですが、技術的には、これは最初のフィールド以外のすべてを印刷する方法の質問には答えません。
Dan Molding

@DanMoulding:ファイルが2つのスペースを使用して国コードを分離し、他に2つのスペースが一緒に出現しない限り、私の答え質問に対処します。
追って通知があるまで一時停止。

2
最初のフィールド(質問のタイトルを参照)以外のすべてを印刷する方法を知りたいので、この質問にたどり着く人々はここに来ます。それが私がここに着陸した方法です。あなたの答えは、最初のフィールドに続いて2番目のフィールドを印刷する方法を示しています。これはおそらくOPの特定の状況に対する最良の解決策ですが、最初のフィールド以外のすべてを印刷する方法の一般的な問題は解決しません。
Dan Molding


2

すべてのレコードを次のレコードに移動し、最後のレコードを最初のレコードとして設定します。

$ awk '{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' file
United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

説明

  • a=$1 最初の値を一時変数に保存します。
  • for (i=2; i<=NF; i++) $(i-1)=$i N番目のフィールド値を(N-1)番目のフィールドに保存します。
  • $NF=a最初の値($1)を最後のフィールドに保存します。
  • {}1awkデフォルトのアクションを実行させるための真の条件:{print $0}

このようにして、別のフィールドセパレータがある場合でも、結果は良好です。

$ cat c
AE-United-Arab-Emirates
AG-Antigua-&-Barbuda
AN-Netherlands-Antilles
AS-American-Samoa
BA-Bosnia-and-Herzegovina
BF-Burkina-Faso
BN-Brunei-Darussalam

$ awk 'BEGIN{OFS=FS="-"}{a=$1; for (i=2; i<=NF; i++) $(i-1)=$i; $NF=a}1' c
United-Arab-Emirates-AE
Antigua-&-Barbuda-AG
Netherlands-Antilles-AN
American-Samoa-AS
Bosnia-and-Herzegovina-BA
Burkina-Faso-BF
Brunei-Darussalam-BN

1

最初の突き刺しは、あなたの特定のケースではうまくいくようです。

awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'

1

オプション1

awkの一部のバージョンで動作するソリューションがあります。

awk '{ $(NF+1)=$1;$1="";$0=$0;} NF=NF ' infile.txt

説明:

       $(NF+1)=$1                          # add a new field equal to field 1.
                  $1=""                    # erase the contents of field 1.
                        $0=$0;} NF=NF      # force a re-calc of fields.
                                           # and use NF to promote a print.

結果:

United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

ただし、それは古いバージョンのawkでは失敗する可能性があります。


オプション2

awk '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

あれは:

awk '{                                      # call awk.
       $(NF+1)=$1;                          # Add one trailing field.
                  $1="";                    # Erase first field.
                        sub(OFS,"");        # remove leading OFS.
                                    }1'     # print the line.

消去する必要があるのはFSではなく、OFSであることに注意してください。このフィールドは、フィールド$ 1が割り当てられると再計算されます。これにより、FSのすべての実行が1つのOFSに変更されます。


しかし、OFSを変更することで明確に示されているように、そのオプションでもいくつかの区切り文字で失敗します。

awk -v OFS=';' '{ $(NF+1)=$1;$1="";sub(OFS,"");}1' infile.txt

その行は出力します:

United;Arab;Emirates;AE
Antigua;&;Barbuda;AG
Netherlands;Antilles;AN
American;Samoa;AS
Bosnia;and;Herzegovina;BA
Burkina;Faso;BF
Brunei;Darussalam;BN

これは、FSの実行が1つのOFSに変更されていることを示しています。
これを回避する唯一の方法は、フィールドの再計算を回避することです。
再計算を回避できる1つの関数はsubです。
最初のフィールドをキャプチャし、subを使用して$ 0から削除し、両方を再印刷できます。

オプション3

awk '{ a=$1;sub("[^"FS"]+["FS"]+",""); print $0, a;}' infile.txt
       a=$1                                   # capture first field.
       sub( "                                 # replace: 
             [^"FS"]+                         # A run of non-FS
                     ["FS"]+                  # followed by a run of FS.
                            " , ""            # for nothing.
                                  )           # Default to $0 (the whole line.
       print $0, a                   # Print in reverse order, with OFS.


United Arab Emirates AE
Antigua & Barbuda AG
Netherlands Antilles AN
American Samoa AS
Bosnia and Herzegovina BA
Burkina Faso BF
Brunei Darussalam BN

FS、OFSを変更したり、区切り文字を追加したりしても機能します。
入力ファイルが次のように変更された場合:

AE..United....Arab....Emirates
AG..Antigua....&...Barbuda
AN..Netherlands...Antilles
AS..American...Samoa
BA..Bosnia...and...Herzegovina
BF..Burkina...Faso
BN..Brunei...Darussalam

そして、コマンドは次のように変わります。

awk -vFS='.' -vOFS=';' '{a=$1;sub("[^"FS"]+["FS"]+",""); print $0,a;}' infile.txt

出力は(まだデリミタを保持)になります。

United....Arab....Emirates;AE
Antigua....&...Barbuda;AG
Netherlands...Antilles;AN
American...Samoa;AS
Bosnia...and...Herzegovina;BA
Burkina...Faso;BF
Brunei...Darussalam;BN

コマンドはいくつかのフィールドに拡張できますが、最新のawksと--re-intervalオプションがアクティブな場合のみです。元のファイルに対するこのコマンド:

awk -vn=2 '{a=$1;b=$2;sub("([^"FS"]+["FS"]+){"n"}","");print $0,a,b;}' infile.txt

これを出力します:

Arab Emirates AE United
& Barbuda AG Antigua
Antilles AN Netherlands
Samoa AS American
and Herzegovina BA Bosnia
Faso BF Burkina
Darussalam BN Brunei

1

別のPerlソリューションを利用できる場合:

perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file

0

sedオプションもあります...

 sed 's/\([^ ]*\)  \(.*\)/\2 \1/' inputfile.txt

説明しました...

Swap
\([^ ]*\) = Match anything until we reach a space, store in $1
\(.*\)    = Match everything else, store in $2
With
\2        = Retrieve $2
\1        = Retrieve $1

より徹底的に説明...

s    = Swap
/    = Beginning of source pattern
\(   = start storing this value
[^ ] = text not matching the space character
*    = 0 or more of the previous pattern
\)   = stop storing this value
\(   = start storing this value
.    = any character
*    = 0 or more of the previous pattern
\)   = stop storing this value
/    = End of source pattern, beginning of replacement
\2   = Retrieve the 2nd stored value
\1   = Retrieve the 1st stored value
/    = end of replacement

0

さらに別の方法...

...これはFSでフィールド2からNFを再結合し、入力の行ごとに1行を出力します

awk '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

私はこれをgitで使用して、作業ディレクトリで変更されたファイルを確認します。

git diff| \
    grep '\-\-git'| \
    awk '{print$NF}'| \
    awk -F"/" '{for (i=2;i<=NF;i++){printf $i; if (i < NF) {printf FS};}printf RS}'

-3

catコマンドを使用する別の簡単な方法

cat filename | awk '{print $2,$3,$4,$5,$6,$1}' > newfilename

これは動的なアプローチではないため、反対票を投じました。これにより、引数の数を把握し、データに一貫性があると想定する必要があります。データはほとんど一貫性がなく、あなたのアプローチはほとんどの場合これを考慮に入れなければなりません。
xh3b4sd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.