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, 여분의 공간없이 루프 앵글없이 할 수 있습니다.
Juan Diego Godoy Robles 2014

답변:


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을 사용하면 공간이 쉽게 제거됩니다.
Santi

107

$1=""Ben Jackson이 언급했듯이 공백을 남기므로 for루프를 사용하십시오 .

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

따라서 문자열이 "one two three"이면 출력은 다음과 같습니다.


결과를 한 행에 표시하려면 다음과 같이 할 수 있습니다.

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

이렇게하면 "둘 셋"이됩니다.


4
그리고 여분의 후행 공백
NeronLeVelu

2
사용하기 더 좋은 방법 : awk '{for(i=2;i<=NF;i++){ printf("%s",( (i>2) ? OFS : "" ) $i) } ; print ;}' 어느 것 : 필드 2를 NF에 인쇄하고 필요에 따라 출력 필드 구분자를 추가합니다 (즉, $ 2 이전 제외). 마지막 인쇄는 현재 줄 인쇄를 끝내기 위해 마지막 줄 바꿈을 추가합니다. 당신이 FS / OFS을 변경하면 하나가 작동합니다 (즉, 항상 "공간"되지 않습니다)
올리비에 Dulac

두 번째는 나를 위해 정말 잘 작동했습니다. 첫 번째는 그다지 많지 않습니다. 이유가 확실하지 않습니다. 전체 텍스트를 잘랐습니다.
음성

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와 관련된 질문에 대답하지 않았지만 awk가 중복 공백을 제거하고 cut은 그렇지 않기 때문에 이것이 가장 유용하다는 것을 알았습니다.
Fmstrat 2014 년

19
echo a b c | cut -d' ' -f 2- 인 대안
루이스

2
니스 - --complement 지원하지 않는 맥에 @Luis 솔루션 작품
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,""): 처음 두 작업 후 {$(NF+1)=$1;$1=""}sub를 사용하여 첫 번째 필드 구분 기호를 제거합니다. 최종 인쇄는 암시 적입니다.


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

첫 번째 필드와 구분 기호를 제거하고 결과를 인쇄합니다 ( 70이 아닌 값이므로 $ 0 인쇄).


베스트 답변! 찬성. 그냥 사용하는 것과 어떻게 다른 1가요? 이 패턴의 사용법이 궁금하고 이해하고 싶었습니다. 감사!
Abhijeet Rastogi

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

첫 번째 필드를로 설정하면 의 시작 부분에의 ""단일 복사본이 남습니다 . 단일 문자 (기본적으로 단일 공백) 라고 가정하면 . 그런 다음 저장된 사본을 추가합니다 .OFS$0OFSsubstr($0, 2)$1


6

Perl 솔루션에 개방적이라면 ...

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

한 공백의 입력 / 출력 구분 기호가있는 간단한 솔루션으로 다음을 생성합니다.

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

입력 / 출력 구분 기호가 두 개의 공백이라고 가정합니다.

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 수정 자,이 예에서는 ''(두 공백)로 분할합니다.

  • -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

큰 따옴표 사이에 두 개의 공백이 있습니다.


당면한 상황에 대한 최선의 대답이지만 기술적으로 이것은 첫 번째 필드를 제외한 모든 것을 인쇄하는 방법에 대한 질문에 대한 대답이 아닙니다.
Dan Molding

@DanMoulding : 국가 코드를 구분하기 위해 두 개의 공백을 사용하여 파일이 일관되고 두 개의 공백이 함께 발생 하지 않는 한 내 대답 질문을 해결합니다.
추후 공지가있을 때까지 일시 중지되었습니다.

2
이 질문에 착수 한 사람들은 첫 번째 필드를 제외한 모든 것을 인쇄하는 방법을 알고 싶어하기 때문에 여기에 온다 (질문 제목 참조). 그것이 내가 여기에 착륙 한 방법입니다. 귀하의 대답은 첫 번째 필드와 두 번째 필드를 인쇄하는 방법을 보여줍니다. 이것이 OP의 특정 상황에 대한 최상의 솔루션 일 수 있지만 첫 번째 필드를 제외한 모든 것을 인쇄하는 방법에 대한 일반적인 문제를 해결하지는 못합니다.
Dan Molding

2

awk '{ tmp = $1; sub(/^[^ ]+ +/, ""); print $0, tmp }'


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기본 작업 을 수행 하기위한 true 조건 : {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 실행이 하나의 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 실행이 하나의 OFS로 변경되고 있음을 나타냅니다.
이를 피하는 유일한 방법은 필드 재 계산을 피하는 것입니다.
재 계산을 피할 수있는 한 가지 기능은 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와 NF를 통해 필드 2를 다시 결합하고 입력 한 줄당 한 줄을 출력합니다.

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.