web-dev-qa-db-ja.com

最初の3列を除くすべてを印刷する

面倒すぎる:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things
109
hhh

余分な先頭または末尾を追加しないソリューション 空白

awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}'

### Example ###
$ echo '1 2 3 4 5 6 7' |
  awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' |
  tr ' ' '-'
4-5-6-7

Sudo_O は、三項演算子を使用したエレガントな改善を提案しますNF?ORS:OFS

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

EdMorton は、フィールド間の元の空白を保持するソリューションを提供します。

$ echo '1   2 3 4   5    6 7' |
  awk '{ sub(/([^ ]+ +){3}/,"") }1' |
  tr ' ' '-'
4---5----6-7

BinaryZebra は、2つの素晴らしいソリューションも提供します。
(これらのソリューションは、元の文字列の末尾のスペースも保持します)

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

コメントの larsr で与えられる解決策はほぼ正しいです:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print $0}' | tr  ' ' '-'
3-4-5-6-7

これは larsr ソリューションの修正されパラメータ化されたバージョンです。

$ echo '1 2 3 4 5 6 7' | 
  awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print $0}' n=4 | tr ' ' '-'
4-5-6-7

2013年9月以前のその他の回答はすべて素晴らしいですが、スペースを追加します。

47
olibre
awk '{for(i=1;i<4;i++) $i="";print}' file
74
jiju

使用カット

$ cut -f4-13 file

または、awkを主張し、$ 13が最後のフィールドである場合

$ awk '{$1=$2=$3="";print}' file

else

$ awk '{for(i=4;i<=13;i++)printf "%s ",$i;printf "\n"}' file
69
ghostdog74

これを試して:

awk '{ $1=""; $2=""; $3=""; print $0 }'
38
lhf

これを行う正しい方法は、RE間隔を使用することです。これにより、スキップするフィールドの数を単純に指定でき、残りのフィールドのフィールド間スペースを保持します。

例えばこの質問で議論していると思われる入力の形式が与えられた場合、残りのフィールド間の間隔に影響を与えずに最初の3つのフィールドをスキップするには、次のようにします。

$ echo '1   2 3 4   5    6' |
awk '{sub(/([^ ]+ +){3}/,"")}1'
4   5    6

先頭のスペースと空白以外のスペースに対応したいが、デフォルトのFSを使用する場合は、次のようになります。

$ echo '  1   2 3 4   5    6' |
awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1'
4   5    6

文字セットで否定できないREであるFSがある場合は、最初に単一の文字に変換できます(RSはフィールド内に表示できないため、単一の文字である場合はRSが理想的です) 、それ以外の場合はSUBSEPを検討してください)、RE間隔の置換を適用してから、OFSに変換します。例えば「。」のチェーンがフィールドを区切る場合:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1'
4 5 6

OFSが単一の文字であり、入力フィールドに表示できない場合は、次のように減らすことができます。

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6

次に、フィールドを再割り当てするすべてのループベースのソリューションと同じ問題があります-FSはOFSに変換されます。それが問題になる場合は、GNU awksのpatsplit()関数を調べる必要があります。

24
Ed Morton

現在、ほとんどすべての回答が先頭のスペース、末尾のスペース、またはその他のセパレーターの問題を追加しています。区切り記号が空白で、出力区切り記号がawkを使用する単一のスペースである4番目のフィールドから選択するには、次のようになります。

awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' file

開始フィールドをパラメーター化するには、次のようにします。

awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 file

また、終了フィールド:

awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file
10
Chris Seymour
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

入力

1 2 3 4 5 6 7

出力

4 5 6 7
6
user4386814
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'
4
Vetsin

オプション1〜3には、複数の空白に関する問題があります(ただし、単純です)。これが、オプション4と5を開発する理由です。オプション4と5は、複数の空白を問題なく処理します。もちろん、n=0でオプション4または5を使用すると、n=0は分割しないことを意味するため、両方とも先頭の空白を保持します。

オプション1

シンプルなカットソリューション(単一の区切り文字で動作):

$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8

オプション2

Awkの再計算を強制すると、追加された先行スペースの問題(awkの一部のバージョンで機能する)が解決される場合があります。

$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8

オプション3

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

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

ただし、以前の回答はすべて、フィールド間のすべてのFSをOFSに変更します。それに対するいくつかのソリューションを構築しましょう。

オプション4

フィールドと区切り文字を削除するsubを含むループはより移植性が高く、FSからOFSへの変更をトリガーしません。

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

注: "^ [" FS "] *"は、先頭にスペースを含む入力を受け入れます。

オプション5

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

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

カウントnが指定されたフィールドリストをスワップするためにも使用できます。

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

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

注1:["FS"]*は、入力行の先頭スペースを許可するために使用されます。

3
user2350426

私は誰もプレーンシェルを提供したとは信じられません:

while read -r a b c d; do echo "$d"; done < file
3
glenn jackman

Printステートメントの使用を避ける別の方法:

 $ awk '{$1=$2=$3=""}sub("^"FS"*","")' file

Awkでは、条件がtrueの場合、印刷がデフォルトのアクションです。

3

先頭または末尾の空白を追加しないPerlソリューション:

Perl -lane 'splice @F,0,3; print join " ",@F' file

Perlの@F自動分割配列はインデックス0で始まり、awkフィールドは$1で始まります


カンマ区切りデータのPerlソリューション:

Perl -F, -lane 'splice @F,0,3; print join ",",@F' file

Pythonソリューション:

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

1
Chris Koknat

Cutには--complementフラグがあり、列を簡単に(そして高速に)削除できます。結果の構文は、あなたがやりたいことと似ています-ソリューションを読みやすく/理解しやすくします。補完は、連続していない列を削除する場合にも機能します。

$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$
1
Michael Back

私はこの他の可能性を見つけました、多分それはまた有用かもしれません...

awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file

注: 1.表形式データおよび列$ 1から$ 14の場合

0
jgarces

私は最初に非常に支持されたが間違った答えに悩まされたので、そこで答えを書くのに十分であることがわかりました。答えをそれほど複雑にする理由がわからないので、提案された解決策は好きではありません。

私はログを持っていますが、IPアドレスが$ 5を超えると、テキストが増えたり、テキストがなくなったりします。 $ 5以降に何かがある場合、IPアドレスから行末までのすべてが必要です。私の場合、これは実際にはawkプログラムではなく、awk onelinerではないため、awkは問題を解決する必要があります。古い見栄えがよく、最も支持されているが完全に間違った答えを使用して最初の4つのフィールドを削除しようとすると:

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

それは間違った役に立たない応答を吐き出します(実証するために[]を追加しました):

[    37.244.182.218 one two three]

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

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

これにより、目的の出力が生成されます。

[37.244.182.218 one two three]
0
Pila

私にとって、この要求に対する最もコンパクトで準拠したソリューションは

$ a='1   2\t \t3     4   5   6 7 \t 8\t '; 
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'

インスタンスファイルfoo.txtのように処理する行がさらにある場合は、iを0にリセットすることを忘れないでください:

$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt

フォーラムに感謝します。

0
user8008888

カットを使用:

cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>

例:file1を含む場合:car.is.Nice.equal.bmw

実行:cut -d . -f1,3 file1car.is.Niceを出力します

0
zayed