처음 세 열을 제외하고 모두 인쇄


112

너무 번거 로움 :

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

43
그냥 사용할 수없는 이유가 있나요 cut -f3-?
Cascabel

1
@hhh 좋은 사람 .. 요약 답변의 아이디어가 마음에 듭니다.
Chris Seymour

2
@Jefromi - 없습니다 AWK 컷과 라인 버퍼링 문제가 있기 때문에 : stackoverflow.com/questions/14360640/...
sdaau


@Jefromi-또한 작업 cut전에 정규식 이 없으며 {}필드 구분 기호 (가변 수의 공백?)가있는 방법은 더 이상하며 수동으로 지정해야합니다. 나는 OP가 shift N존재하지 않는 명령 에 대해 듣고 싶어했다고 생각 합니다. 가장 가까운 것은 $1="";$2="";(...);print}이지만 제 경우에는 선행 공백 (아마 구분 기호)을 남깁니다.
Tomasz Gandor 2016

답변:


50

추가 선행 또는 후행 공백을 추가하지 않는 솔루션 :

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 는 또한 두 가지 멋진 솔루션을 제공합니다.
(이 솔루션은 원래 문자열의 후행 공백도 보존합니다)

$ 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 월 이전의 다른 모든 답변은 좋지만 공백을 추가하십시오.


EdMorton의 답변은 저에게 효과가 없었습니다 (bash 4.1.2 (1) -release, GNU Awk 3.1.7 또는 bash 3.2.25 (1) -release, GNU Awk 3.1.5). 여기서 다른 방법을 찾았 습니다 .echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

1
@elysch 아니요, 일반적으로 작동하지 않으며 특정 입력 값이 주어지면 작동하는 것처럼 보입니다. 내 답변 아래 귀하의 의견 아래에 추가 한 의견을 참조하십시오.
Ed Morton

1
안녕하세요 @fedorqui. 내 대답이 첫 번째입니다. 내 원래 답변에서 다른 답변이 정확하지 않은 이유를 설명했습니다 (추가 선행 또는 후행 공백). 일부 사람들은 의견 내에서 개선 사항을 제안했습니다. OP에게 더 정답을 선택하도록 요청했으며 내 답변을 선택했습니다. 다른 기여자가 대답을 참조하기 위해 내 대답을 편집 한 후 (역사 참조). 당신에게 분명합니까? 내 답변의 이해도를 높이기 위해 무엇을 조언합니까? 건배 ;-)
olibre

1
당신은 절대적으로 옳고 내 오해에 대해 매우 죄송합니다. 나는 대답을 빨리 읽었고 당신의 원래 대답을 눈치 채지 못했습니다 (예, 너무 빨리 읽었습니다). NF-1까지 반복하는 멋진 트릭을 사용하여 대답 자체에 +1을 한 다음 추가 공백을 피하기 위해 마지막 요소를 인쇄합니다. 그리고 다시 한번 죄송합니다! (향후 독자의 오해를 방지하기 위해 하루 정도 내 댓글을 삭제합니다).
fedorqui 'SO stop harming'2016

1
나는 어떤 종류의 헤더를 사용할 것입니다 : <your answer> 그리고 그 다음에는 "다른 답변의 비교"라는 큰 제목이 뒤 따르는 수평 규칙이 있습니다. 그렇지 않으면이 비교를 다른 답변으로 옮기십시오. 사람들은 "내 코드를

75
awk '{for(i=1;i<4;i++) $i="";print}' file

4
즉, 레코드의 선행 공백을 OFS처리하지 않으므로 선행이 남습니다 NF.
Chris Seymour

70

컷 사용

$ cut -f4-13 file

또는 awk를 고집하고 $ 13이 마지막 필드 인 경우

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

그밖에

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

14
마지막 예에서 "13"보다 "NF"를 사용하는 것이 좋습니다.
glenn jackman

2
OP가 결정하는 2 가지 시나리오. 13이 마지막 필드이면 NF를 사용하는 것이 좋습니다. 그렇지 않은 경우 13을 사용하는 것이 적절합니다.
ghostdog74 2010

3
두 번째는 $ 0 시작부터 3 개의 OFS 사본을 삭제해야합니다. 3 더 함께 할 것입니다 printf "%s ",$i당신이 여부를 알 수 없기 때문에, $i이 포함될 수 있습니다 %s등 나. 그러나 그것은 끝에 여분의 공간을 인쇄합니다.
dubiousjim

38

이 시도:

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

1
이것은 그것이 얼마나 역동적이기 때문에 좋습니다. 끝에 열을 추가하고 스크립트를 다시 작성할 수 없습니다.
MinceMan

1
이것은 질문이 당신을 처리하려는 정확한 문제를 보여줍니다. 100 번째 필드에서 인쇄하는 것은 어떻습니까? 당신이 처리하지 않기 NF때문에 선두를 떠나는 것을 언급하십시오 OFS.
Chris Seymour

24

이를 수행하는 올바른 방법은 단순히 건너 뛸 필드 수를 지정하고 나머지 필드에 대한 필드 간 간격을 유지하기 때문에 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 () 함수를 살펴 봐야합니다.


나를 위해 작동하지 않았지만 (bash 4.1.2 (1) -release, GNU Awk 3.1.7 또는 bash 3.2.25 (1) -release, GNU Awk 3.1.5) 여기서 다른 방법을 찾았 습니다 .echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

2
아니요, $ 1 또는 $ 2에 $ 3이 설정된 문자열이 포함되어 있으면 실패합니다. 예를 들어 시도해 보면 $ 3 이 $ 1 의 내부 와 일치한다는 것을 echo ' That is a test' | awk '{print substr($0, index($0,$3))}'알 수 있습니다. 매우 오래된 gawk 버전에서는 플래그를 사용하여 RE 간격을 활성화해야합니다 . aaThat--re-interval
Ed Morton

2
당신 말이 맞아요. 그건 그렇고, 정말 당신의 의견에 감사드립니다. 여러 번 "{}"와 함께 정규식을 사용하여 요소 수를 지정하고 싶었지만 사람에서 "-재 간격"을 보지 못했습니다. 당신을 위해 +1.
elysch

1
1true 조건이므로 현재 레코드를 인쇄하는 기본 awk 작업을 호출합니다.
Ed Morton

1
그것이 얼마나 표준인지 idk하지만 지금 대답을 추가했습니다.
Ed Morton

10

거의 모든 답변은 현재 선행 공백, 후행 공백 또는 기타 구분 기호 문제를 추가합니다. 구분자가 공백이고 출력 구분자가 단일 공백 ​​인 네 번째 필드에서 선택하려면 다음을 사용 awk합니다.

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

6
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

입력

1 2 3 4 5 6 7

산출

4 5 6 7

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

3
또는 같은 줄에 표시하려면 $ 3을 $ 1 등에 할당 한 다음 NF를 올바른 필드 수로 변경합니다. echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr

안녕하세요 @larsr. 제안한 명령 줄은 하나의 정답입니다. 다른 모든 답변은 추가 공백 (선행 또는 후행)을 추가합니다. 새 답변에 명령 줄을 게시하십시오. 찬성 투표하겠습니다 ;-)
olibre

1
안녕하세요 @sudo_O, 저는 @larsr에게 그가 그의 의견에서 제안한 명령 줄에 대해 이야기하고있었습니다. 나는 퀴 프로 코 (오해)를 알아 내기까지 약 5 분을 보냈다. 동의합니다. @Vetsin 답변 ORS은 필드 사이에 새 줄 ( )을 삽입 합니다. 당신의 이니셔티브에 대한 브라보 (나는 당신의 대답을 좋아합니다). 건배
olibre

3

print 문 사용을 피하는 또 다른 방법 :

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

조건이 참일 때 awk에서 print가 기본 동작입니다.


이것은 @lhf 대답 이 가진 모든 문제를 가지고 있습니다.
Chris Seymour

아주 좋은 생각;) 내 대답보다 낫다! (나는 이미 작년에 귀하의 답변을 upvoted했습니다) Cheers
olibre

awk '{$1=$2=$3=""}sub("^"OFS"+","")' file$ 1, $ 2 및 $ 3 내용을 변경 한 후 남은 OFS는 다음 과 같아야합니다 .

3

아무도 일반 쉘을 제공하지 않았다는 것을 믿을 수 없습니다.

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

비슷한 솔루션의 경우 +1 ... 그러나이 file크기가 크면 (> 10-30KiB) 성능 문제가있을 수 있습니다 . 대용량 파일의 경우 awk솔루션이 더 잘 수행됩니다.
TrueY

3

옵션 1 ~ 3에는 다중 공백 문제가 있습니다 (단순함). 이것이 문제없이 여러 개의 공백을 처리하는 옵션 4와 5를 개발 한 이유입니다. 물론, 옵션 4 또는 5가 n=0둘 다 와 함께 사용 되면 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

추가 선행 또는 후행 공백을 추가하지 않고 gensubGNU awk 의 함수 를 사용하여 기존 공백을 유지하는 솔루션을 구축하는 것이 가능합니다 .

$ 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"]* 입력 줄에 선행 공백을 허용하는 데 사용됩니다.


안녕하세요 BZ 귀하의 답변은 좋습니다. 그러나 옵션 3은 공백 (예 :)으로 시작하는 문자열에서 작동하지 않습니다 " 1 2 3 4 5 6 7 8 ". 옵션 4는 좋지만 공백으로 시작하는 문자열을 사용하여 선행 공백을 남겨 둡니다. 이것이 고칠 수 있다고 생각하십니까? 명령 echo " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'을 사용 하여 선행 / 중간 / 후행 공백을 확인할 수 있습니다 ... Cheers;)
olibre

안녕하세요 @olibre. 옵션 3이 공백으로 인해 실패한다는 것이 옵션 4와 5를 개발하는 이유입니다. 옵션 4는 입력에 공백이 있고 n이 0 (n = 0)으로 설정된 경우에만 선행 공백을 남깁니다 . 필드 선택이 없을 때 정답이라고 생각합니다 (IMO를 수정할 것이 없음). 건배.

괜찮아. 덕분에 추가 정보를 :-) 이러한 추가 정보를 원하시면 :-) 건배 제공하는 답변을 향상하십시오
olibre

Perfect :-) 귀하의 사용자가 비활성화
되어서

1

Cut에는 열을 쉽고 빠르게 삭제할 수있는 --complement 플래그가 있습니다. 결과 구문은 수행하려는 작업과 유사하므로 솔루션을 더 쉽게 읽고 이해할 수 있습니다. 연속되지 않은 열을 삭제하려는 경우에도 보완이 작동합니다.

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

더 많은 답변을 설명해 주시겠습니까?
Zulu

위의 편집 내용이 이해에 도움이됩니까? 요점은 컷의 보완 플래그를 사용하는 것입니다. 솔루션은 AWK 또는 perl 기반 솔루션보다 더 빠르고 간결한 구현이어야합니다. 또한 임의의 열을자를 수 있습니다.
Michael Back

1

선행 또는 후행 공백을 추가하지 않는 Perl 솔루션 :

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

perl @Fautosplit 배열은 인덱스에서 시작하고 0awk 필드는 다음으로 시작합니다.$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


0

저에게 가장 컴팩트하고 규정을 준수하는 솔루션은

$ 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

나는 처음으로 크게 찬성했지만 잘못된 답변에 짜증이 나서 거기에 답글을 쓸만큼 충분히 찾았고 여기에 잘못된 답변이 표시되어 있습니다. 답을 그렇게 복잡하게 만들 이유가 없기 때문에 제안 된 해결책이 마음에 들지 않습니다.

IP 주소가있는 $ 5 이후에 더 많은 텍스트가 있거나 텍스트가 없을 수있는 로그가 있습니다. $ 5 이후에 아무것도 없으면 IP 주소에서 줄 끝까지 모든 것이 필요합니다. 제 경우에는 awk oneliner가 아니라 awk 프로그램이있는 경우 실제로 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

이 다른 가능성을 찾았습니다. 아마도 유용 할 수도 있습니다.

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

참고 : 1. 테이블 형식 데이터 및 $ 1부터 $ 14까지


0

컷 사용 :

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 file1 인쇄합니다car.is.nice


귀하의 솔루션이 거꾸로 된 것 같습니다. 질문 제목 검토하십시오 처음 세 열을 모두 * 인쇄하지만 *
스테판 Crain

-1

이것은 이전 답변 중 일부와 그리 멀지 않지만 몇 가지 문제를 해결합니다.

cols.sh:

#!/bin/bash
awk -v s=$1 '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }'

이제 시작 열이 될 인수로 호출 할 수 있습니다.

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 
3    4    5    6    7    8    9    10   11   12   13   14

또는:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 
7    8    9    10   11   12   13   14

이것은 1 색인입니다. 제로 인덱스를 선호하는 경우 i=s + 1대신 사용하십시오.

또한 시작 색인 끝 색인에 대한 인수가 필요 하면 파일을 다음과 같이 변경하십시오.

#!/bin/bash
awk -v s=$1 -v e=$2 '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }'

예를 들면 :

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 
7    8    9

%-5s가지런 5 문자 폭 열로 결과; 이것이 충분하지 않으면 숫자를 늘리거나 %s정렬에 관심이 없으면 대신 공백을 사용하십시오.


-1

% 문제를 방지하고 인쇄 할 열이 4 개 미만인 경우 아무것도 반환하지 않는다는 점에서 고유 한 AWK printf 기반 솔루션 :

awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'

테스트 :

$ x='1 2 3 %s 4 5 6'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
%s 4 5 6
$ x='1 2 3'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$ x='1 2 3 '
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.