awkを使用してn番目から最後までのすべての列を出力する


310

この行は、2番目のフィールドに空白ができるまで機能しました。

svn status | grep '\!' | gawk '{print $2;}' > removedProjs

awkにすべてを$ 2以上で印刷させる方法はありますか?($ 3、$ 4 ..列がなくなるまで?)

Cygwinを使用するWindows環境でこれを実行していることを追加する必要があると思います。


11
余談として、grep | awkアンチパターンである -あなたがしたいawk '/!/ { print $2 }'
tripleee

3
Unixの「カット」の方が簡単です...svn status | grep '\!' | cut -d' ' -f2- > removedProjs
roblogic


@tripleee:あなたがこれを言ってくれてとてもうれしいです-私はどこでもそれを見るのにイライラしています!
Graham Nicholls、2018年

回答:


490

最初の列を除くすべてを出力します:

awk '{$1=""; print $0}' somefile

最初の2列を除くすべてを印刷します。

awk '{$1=$2=""; print $0}' somefile

93
gotcha::(
raphinesseの2013年

5
私は実用的なアプローチが好きです。ただし、catを使用する必要はありません。awkコマンドの後にファイル名を置くだけです。
2013年

45
@raphinesseで修正できますawk '{$1=""; print substr($0,2)}' input_filename > output_filename
themiurgo

6
これは空白以外の区切り文字では機能せず、空白で置き換えます。
Dejan 2013年

3
空白以外の区切り文字の場合は、出力フィールド区切り文字(OFS)をコンマなどに指定できます。awk -F, -vOFS=, '{$1=""; print $0}'最終的には、最初の区切り文字($1空の文字列として含まれます)になります。あなたはストリップできることとsedいえ:awk -F, -vOFS=, '{$1=""; print $0}' | sed 's/^,//'
cherdt

99

カットを使用してより簡単な答えを持つ重複した質問があります:

 svn status |  grep '\!' | cut -d\  -f2-

-d区切り文字(スペース)-f指定し、列のリストを指定します(すべて2番目から始まる)。


「-b」を使用して、位置を指定することもできます(N番目の文字以降)。
ダカチン2013

注意点としては、このように行って同じタスクがawkバージョン、ラインバッファリングの問題がであるcutこれ、awk:ありませんstackoverflow.com/questions/14360640/...を
sdaau

24
素晴らしくシンプルですが、注意点がありますawk。隣接する複数のスペース文字を扱います。単一のセパレータとしてcut。また、これは当面の問題ではありませんがcut、単一のリテラル文字のみを受け入れます。区切り文字として、awk正規表現を許可します。
mklement0 2014年

これに基づいて:stackoverflow.com/a/39217130/8852408、このソリューションはあまり効率的ではない可能性があります。
FcknGioconda

85

forループを使用して、$ 2から$ NF(行のフィールド数を表す組み込み変数)までの印刷フィールドをループできます。

編集:「印刷」は改行を追加するので、結果をバッファリングする必要があります。

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

または、printfを使用します。

awk '{for(i=2;i<=NF;i++){printf "%s ", $i}; printf "\n"}'

だから私はこれを試しましたが、何かが足りないのではないかと思います。grep '\!' | gawk '{for(i = 1; i <= $ NF; i ++)print $ i "";}'> deletedProjs
Andy

printは改行を追加するので、結果をバッファリングする必要があります。私の編集を参照してください。
VeeArr

1
フィールドをループする方法を示しているので、私はこの答えがより好きです。
Edward Falk

3
印刷でスペースを使用する場合は、出力レコードの区切り記号を変更します。awk '{ORS = ""; for(i = 2; i <NF; i ++)print $ i} 'somefile
Christian Lescuyer

3
常にスペースが多すぎます。これはよりよく機能します:'{for(i=11;i<=NF-1;i++){printf "%s ", $i}; print $NF;}'先頭または末尾にスペースはありません。
Marki

24
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'

私の答えはVeeArrの1つに基づいてますが、2列目(および残りの列)を印刷する前に空白で始まっていることに気付きました。私は評判ポイントが1つしかないので、コメントすることはできません。そのため、これは新しい答えになります。

2番目の列が「out」で始まり、他のすべての列(存在する場合)を追加します。これは、2番目の列がある限りうまくいきます。


2
また、重要なout変数の前の$も削除しました。
Alexis Wilke、2014

15

awkを使用したほとんどのソリューションはスペースを残します。ここのオプションはその問題を回避します。

オプション1

簡単なカットソリューション(単一の区切り文字でのみ機能します):

command | cut -d' ' -f3-

オプション2

awkの再計算を強制すると、最初のフィールドが削除されて残った追加の先行スペース(OFS)が削除される場合があります(awkの一部のバージョンで機能します)。

command | awk '{ $1=$2="";$0=$0;} NF=NF'

オプション3

でフォーマットされた各フィールドを印刷するprintfと、より詳細に制御できます。

$ in='    1    2  3     4   5   6 7     8  '
$ echo "$in"|awk -v n=2 '{ for(i=n+1;i<=NF;i++) printf("%s%s",$i,i==NF?RS:OFS);}'
3 4 5 6 7 8

ただし、以前のすべての回答は、フィールド間で繰り返されるすべてのFSをOFSに変更します。それを行わないオプションをいくつか作成しましょう。

オプション4(推奨)

前部のフィールドと区切り文字を削除するsubを含むループ。
そして、スペースの代わりにFSの値を使用します(変更される可能性があります)。
より移植性がある、とOFSへのFSの変化をトリガしません: 注:^[FS]*先頭のスペースで入力を受け入れることです。

$ in='    1    2  3     4   5   6 7     8  '
$ echo "$in" | awk '{ n=2; a="^["FS"]*[^"FS"]+["FS"]+";
  for(i=1;i<=n;i++) sub( a , "" , $0 ) } 1 '
3     4   5   6 7     8

オプション5

以下のようにgensub、GNU awk の関数を使用して、余分な(先頭または末尾の)空白を追加せず、既存の空白を保持するソリューションを構築することはかなり可能です。

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
          { print(gensub(a""b""c,"",1)); }'
3     4   5   6 7     8 

カウントを指定してフィールドのグループを交換するために使用することもできますn

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=2 'BEGIN{ a="^["FS"]*"; b="([^"FS"]+["FS"]+)"; c="{"n"}"; }
          {
            d=gensub(a""b""c,"",1);
            e=gensub("^(.*)"d,"\\1",1,$0);
            print("|"d"|","!"e"!");
          }'
|3     4   5   6 7     8  | !    1    2  !

もちろん、そのような場合、OFSは行の両方の部分を分離するために使用され、フィールドの末尾の空白は引き続き印刷されます。

注: [FS]*入力行で先行スペースを許可するために使用されます。


13

私は個人的に上記のすべての答えを試しましたが、それらのほとんどは少し複雑であるか、正しくありませんでした。私の観点からそれを行う最も簡単な方法は次のとおりです。

awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
  1. ここで、-F ""は、awkが使用する区切り文字を定義します。私の場合は空白です。これはawkのデフォルトの区切り文字でもあります。つまり、-F ""は無視できます。

  2. ここで、NFはフィールド/列の総数を定義します。したがって、ループは4番目のフィールドから最後のフィールド/列まで始まります。

  3. $ NはN番目のフィールドの値を取得します。したがって、print $ iはループカウントに基づいて現在のフィールド/列を印刷します。


4
問題は、各フィールドを別の行に出力することです。
mveroone 2015

これを最後に追加するのを止めるものは何もありません:-) `| tr '\ n' '' `
koullislp

3
少し遅れてawk '{for(i = 5; i <= NF; i ++){printf "%s"、$ i}}'
plitter


7

これは私をとても苛立たせました、私は座って、cutGNU Awk 3.1.7でテストされたようなフィールド仕様パーサーを書きました。

まず、と呼ばれる新しいAwkのライブラリスクリプトを作成するpfcutなどして、

sudo nano /usr/share/awk/pfcut

次に、以下のスクリプトを貼り付けて保存します。その後、次のように使用します。

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

入力をすべて回避するために、最善の方法(そうでない場合は、起動時にawkを使用してユーザー関数を自動的に読み込む?-Unix&Linux Stack Exchangeを参照)にエイリアスを追加し~/.bashrcます。例:

$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc     # refresh bash aliases

...それからあなたはただ呼び出すことができます:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

pfcutスクリプトのソースは次のとおりです。

# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013

function spfcut(formatstring)
{
  # parse format string
  numsplitscomma = split(formatstring, fsa, ",");
  numspecparts = 0;
  split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
  for(i=1;i<=numsplitscomma;i++) {
    commapart=fsa[i];
    numsplitsminus = split(fsa[i], cpa, "-");
    # assume here a range is always just two parts: "a-b"
    # also assume user has already sorted the ranges
    #print numsplitsminus, cpa[1], cpa[2]; # debug
    if(numsplitsminus==2) {
     if ((cpa[1]) == "") cpa[1] = 1;
     if ((cpa[2]) == "") cpa[2] = NF;
     for(j=cpa[1];j<=cpa[2];j++) {
       parts[numspecparts++] = j;
     }
    } else parts[numspecparts++] = commapart;
  }
  n=asort(parts); outs="";
  for(i=1;i<=n;i++) {
    outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS); 
    #print(i, parts[i]); # debug
  }
  return outs;
}

function pfcut(formatstring) {
  print spfcut(formatstring);
}

使用したくcutないようですawk
roblogic

5

#2から始まる列を出力します(出力の先頭に末尾のスペースはありません)。

ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'

1
+フィールドawkは複数のスペースで区切られている可能性があるため、スペースの後に追加する必要があります(隣接する複数のスペースを単一のセパレーターとして扱います)。また、awk先頭のスペースは無視されるため、正規表現はで始める必要があり^[ ]*ます。スペースをセパレータとして使用すると、ソリューションを一般化することもできます。たとえば、次の例では、3番目のフィールドからすべてが返されawk '{sub(/^[ ]*([^ ]+ +){2}/, ""); print $0}'ます。
mklement0 2014年

5

これはうまくいくでしょうか?

awk '{print substr($0,length($1)+1);}' < file

ただし、前に空白が残っています。



3

これは私がすべての推奨事項から選んだものです:

6列目から最終列まで印刷。

ls -lthr | awk '{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}'

または

ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'

2

任意の区切り文字で印刷された特定の列が必要な場合:

awk '{print $3 "  " $4}'

col#3 col#4

awk '{print $3 "anything" $4}'

col#3anythingcol#4

したがって、列に空白がある場合は2列になりますが、任意の区切り文字を使用して、または使用せずに接続できます。


2

Perlソリューション:

perl -lane 'splice @F,0,1; print join " ",@F' file

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

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

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

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

  • -e Perlコードを実行する

splice @F,0,1 @F配列から列0をきれいに削除します

join " ",@F @F配列の要素を、各要素の間にスペースを入れて結合します


Pythonソリューション:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[1:]) + '\n') for line in sys.stdin]" < file


1

行の一部を切り取らないで再フォーマットしたくない場合、私が考えることができる最良の解決策は私の答えに書かれています:

awkを使用して特定の番号の後にすべての列を印刷する方法は?

これは、指定されたフィールド番号Nの前のものを切り取り、フィールド番号Nを含み、元の間隔を維持して、行の残りのすべてを印刷します(再フォーマットしません)。フィールドの文字列が行の他の場所にも表示される場合は問題ありません。

関数を定義します。

fromField () { 
awk -v m="\x01" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

次のように使用します。

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

出力は、末尾のスペースを含むすべてを維持します

あなたの特定のケースでは:

svn status | grep '\!' | fromField 2 > removedProjs

ファイル/ストリームの行の途中に改行文字が含まれていない場合(別のレコードセパレーターを使用している可能性があります)、次を使用できます。

awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

最初のケースは、まれな16進文字番号1を含むファイル/ストリームでのみ失敗します。


0

これは、Bashを使用していて、破棄したい要素と同じ数の「x」を使用でき、エスケープされていない場合は複数のスペースを無視する場合に機能します。

while read x b; do echo "$b"; done < filename

0

Perl:

@m=`ls -ltr dir | grep ^d | awk '{print \$6,\$7,\$8,\$9}'`;
foreach $i (@m)
{
        print "$i\n";

}

1
これは、N番目の列から最後まで印刷する要件を一般化する質問には答えません。
roaima 2015年

0

このawk関数は$0begin〜のフィールドを含むの部分文字列を返しますend

function fields(begin, end,    b, e, p, i) {
    b = 0; e = 0; p = 0;
    for (i = 1; i <= NF; ++i) {
        if (begin == i) { b = p; }
        p += length($i);
        e = p;
        if (end == i) { break; }
        p += length(FS);
    }
    return substr($0, b + 1, e - b);
}

すべてをフィールド3から始めるには、

tail = fields(3);

そのセクションを取得$0するには、フィールド3〜5をカバーします。

middle = fields(3, 5);

b, e, p, i関数パラメーターリストのawk意味がないのは、ローカル変数を宣言する方法にすぎません。


0

提案された回答を、フィールドが複数の空白で区切られている可能性がある状況に拡張したいcutと思います。これは、OPが使用されていない理由だと思います。

OPがについて尋ねたことは知ってawkいますが、sedここではアプローチが機能します(5番目から最後までの列を印刷する例):

  • 純粋なsedアプローチ

    sed -r 's/^\s*(\S+\s+){4}//' somefile

    説明:

    • s/// 置換を実行する標準的な方法が使用されます
    • ^\s* 行頭の連続する空白にマッチします
    • \S+\s+ データの列を意味します(非空白文字とそれに続く空白文字)
    • (){4} パターンが4回繰り返されることを意味します。
  • セッドとカット

    sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-

    連続する空白を1つのタブに置き換えるだけ。

  • trおよびcut: オプションをtr使用して、連続する文字をスクイーズするためにも使用でき-sます。

    tr -s [:blank:] <somefile | cut -d' ' -f5-

-1

Awkの例はここでは複雑に見えますが、これは単純なBashシェル構文です。

command | while read -a cols; do echo ${cols[@]:1}; done

どこに1あなたのであるnが 0から列目のカウント。


このファイルのコンテンツ(in.txt)を考えると:

c1
c1 c2
c1 c2 c3
c1 c2 c3 c4
c1 c2 c3 c4 c5

ここに出力があります:

$ while read -a cols; do echo ${cols[@]:1}; done < in.txt 

c2
c2 c3
c2 c3 c4
c2 c3 c4 c5

-1

awk最初の数列を抽出してから残りを印刷したかったので、ここに示した解決策のいずれにも満足していなかったため、perl代わりに変更しました。次のコードは、最初の2つの列を抽出し、残りをそのまま表示します。

echo -e "a  b  c  d\te\t\tf g" | \
  perl -ne 'my @f = split /\s+/, $_, 3; printf "first: %s second: %s rest: %s", @f;'

Chris Koknatperlソリューションと比較した場合の利点は、実際には最初のn個の要素のみが入力文字列から分割されることです。文字列の残りの部分はまったく分割されないため、完全にそのまま残ります。私の例では、スペースとタブを組み合わせてこれを示しています。

抽出する列の数を変更するに3は、例のをn + 1 に置き換えます。


-1
ls -la | awk '{o=$1" "$3; for (i=5; i<=NF; i++) o=o" "$i; print o }'

この答えから悪くはありませんが、自然な間隔がなくなっています。
次に、これと比較してください。

ls -la | cut -d\  -f4-

次に、違いがわかります。

でもls -la | awk '{$1=$2=""; print}'に基づいている答えは、これまでに書式を保持されていない最高の投票しました。

したがって、私は以下を使用し、最初に明示的な選択列も許可します。

ls -la | cut -d\  -f1,4-

すべてのスペースも列にカウントされることに注意してください。たとえば、以下では、列1と3は空で、2はINFO、4は次のようになります。

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f1,3

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f2,4
INFO 2014-10-11
$

-1

フォーマットされたテキストが必要な場合は、コマンドをエコーでチェーンし、$ 0を使用して最後のフィールドを出力します。

例:

for i in {8..11}; do
   s1="$i"
   s2="str$i"
   s3="str with spaces $i"
   echo -n "$s1 $s2" | awk '{printf "|%3d|%6s",$1,$2}'
   echo -en "$s3" | awk '{printf "|%-19s|\n", $0}'
done

プリント:

|  8|  str8|str with spaces 8  |
|  9|  str9|str with spaces 9  |
| 10| str10|str with spaces 10 |
| 11| str11|str with spaces 11 |

-9

340票の間違った最も支持されたanwserのため、私はちょうど私の人生の5分を失いました!これを賛成する前に誰かがこの答えを試しましたか?ありません。まったく役に立たない。

$ 5の後にIPアドレスを入力すると、テキストが増える場合とない場合があります。$ 5より後のものがあれば、IPアドレスから行末まですべてが必要です。私の場合、これは実際にはawkプログラムではなくawkワンライナーなので、awkが問題を解決する必要があります。最も投票されたが完全に間違った答えを使用して最初の4つのフィールドを削除しようとすると:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'

それは間違って役に立たない応答を吐き出します(私は[..]を追加して説明します)

[    37.244.182.218 one two three]

substrとこの間違った答えを組み合わせるいくつかの提案もあります。そのような複雑さは改善です。

代わりに、カットポイントとawkが必要になるまで列の幅が固定されている場合、正しい答えは次のとおりです。

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218" | awk '{printf "[%s]\n", substr($0,28)}'

これにより、必要な出力が生成されます。

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