次のようなファイルがあります。
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以外のすべて」トリックを行うにはどうすればよいですか?
$1
を割り当てることはできますが、先頭にスペースが残ります:awk '{first = $1; $1 = ""; print $0, first; }'
NF
で列の数を検索し、ループで使用することもできます。
$1=""
はBen Jacksonが述べたようにスペースを残すので、for
ループを使用します。
awk '{for (i=2; i<=NF; i++) print $i}' filename
したがって、文字列が「1、2、3」の場合、出力は次のようになります。
二
三
結果を1行に収めるには、次のようにします。
awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}' filename
これにより、「two three」が得られます。
--complement
オプションを指定してcut
コマンドを使用します。
$ 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
たぶん最も簡潔な方法:
$ 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を使用して最初のフィールド区切り文字を取り除きます。最終的な印刷は暗黙的です。
awk '{sub($1 FS,"")}7' YourFile
最初のフィールドと区切り文字を削除し、結果を出力します(7
はゼロ以外の値なので、$ 0を出力します)。
awk '{ saved = $1; $1 = ""; print substr($0, 2), saved }'
最初のフィールドを""
に設定すると、$0
の先頭にOFS
の単一のコピーが残ります。 OFS
が単一の文字(デフォルトでは単一のスペース)であると仮定すると、substr($0, 2)
で削除できます。次に、保存された$1
のコピーを追加します。
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までの配列スライスです。
(少なくとも)gawkのフィールド区切り文字には、文字列と文字(正規表現も使用可能)を指定できます。データに一貫性がある場合、これは機能します。
awk -F " " '{print $2,$1}' inputfile
これは、二重引用符の間の2つのスペースです。
awk '{ tmp = $1; sub(/^[^ ]+ +/, ""); print $0, tmp }'
すべてのレコードを次のレコードに移動し、最後のレコードを最初のレコードに設定しましょう。
$ 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
)を最後のフィールドに保存します。{}1
真の条件でawk
がデフォルトアクション{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
別のPerlソリューションを開いている場合:
Perl -ple 's/^(\S+)\s+(.*)/$2 $1/' file
最初の突き刺しは、特定のケースで機能するようです。
awk '{ f = $1; i = $NF; while (i <= 0); gsub(/^[A-Z][A-Z][ ][ ]/,""); print $i, f; }'
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の古いバージョンでは失敗する場合があります。
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から削除してから、両方を再印刷できます。
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
さらに別の方法...
...これは、フィールド2からNFをFSで再結合し、入力の行ごとに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}'
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