구분 된 문자열을 awk의 배열로 나누는 방법은 무엇입니까?


169

파이프 기호 |가 포함 된 문자열을 분할하는 방법 그것들을 배열로 나누고 싶습니다.

나는 시도했다

echo "12:23:11" | awk '{split($0,a,":"); print a[3] a[2] a[1]}'

어느 것이 잘 작동합니까? 내 문자열이 같다면 "12|23|11"어떻게 배열로 나눌 수 있습니까?


3
출력은 구분 기호없이 배열 요소를 연결합니다. 대신로 구분하기를 원한다면 OFS쉼표를 붙여서 print별도의 인수로 확인하십시오.
dubiousjim

또는 sed를 사용할 수 있습니다 :echo "12:23:11" | sed "s/.*://"
slushy

@ slushy : 당신의 명령은 아 수르가 필요로하는 것이 아닙니다. 귀하의 명령 ( echo "12:23:11" | sed "s/.*://")은 마지막 ":"까지 모든 것을 삭제하고 "11"만 유지합니다 ... 마지막 숫자를 얻으려면 작동하지만 읽기 어려운 방식으로 수정해야합니다. 두 번째 숫자 등 awk (및 awk의 분할)는 훨씬 더 우아하고 읽기 쉽습니다.
Olivier Dulac

단일 문자로 분할해야하는 경우 다음을 사용할 수 있습니다cut
ccpizza

답변:


274

시도해 보셨습니까?

echo "12|23|11" | awk '{split($0,a,"|"); print a[3],a[2],a[1]}'

2
@Mohamed Saligh, Solaris를 사용 하는 경우 문자열 길이에 따라 / usr / xpg4 / bin / awk를 사용해야 합니다.
Dimitre Radoulov

5
'나를 위해 작동하지 않습니다'. 특히 에코 값과 콜론 사이의 콜론과 '|'? 오식? 모두에게 행운을 빕니다.
shellter

1
구문 설명이 더 좋습니다.
Alston

2
GNU awk에서는 작동하지 않습니다. 왜냐하면 세 번째 인수 split는 정규식 |이며 특수 기호이므로 이스케이프해야합니다. 사용split($0, a, "\|")
WhiteWind

1
@WhiteWind : |문자로 표시되고 특수 기호가 아닌 "보장"하는 또 다른 방법 은 []다음 split($0, a, "[|]") 과 같이 사이에 두는 것입니다 . 펄 대 grep 대 .. 다른 사람?) "|" 문자 그대로 해석하고 "\ |" 대신 반대 ... YMMV의 정규식 구분으로 볼
올리비에 Dulac

119

문자열을 배열로 나누려면 awk함수를 사용하십시오 split().

 awk '{split($0, a, ":")}'
 #           ^^  ^  ^^^
 #            |  |   |
 #       string  |   delimiter
 #               |
 #               array to store the pieces

구분 기호를 지정하지 않으면 FS공백이 기본값으로 사용 됩니다.

$ awk '{split($0, a); print a[2]}' <<< "a:b c:d e"
c:d

예를 들어 구분 기호를 제공 할 수 있습니다 :.

$ awk '{split($0, a, ":"); print a[2]}' <<< "a:b c:d e"
b c

다음을 통해 설정하는 것과 같습니다 FS.

$ awk -F: '{split($0, a); print a[1]}' <<< "a:b c:d e"
b c

gawk에서는 구분 기호를 정규 표현식으로 제공 할 수도 있습니다.

$ awk '{split($0, a, ":*"); print a[2]}' <<< "a:::b c::d e" #note multiple :
b c

그리고 네 번째 매개 변수를 사용하여 모든 단계에서 구분 기호가 무엇인지 확인하십시오.

$ awk '{split($0, a, ":*", sep); print a[2]; print sep[1]}' <<< "a:::b c::d e"
b c
:::

GNU awkman 페이지를 인용 해 봅시다 :

split (문자열, 배열 [, fieldsep [, seps]])

문자열fieldsep 로 구분 된 조각으로 나누고 조각을 배열에 저장 하고 구분자 문자열을 seps 배열에 저장합니다. 첫번째 조각에 저장되고 array[1], 두 번째 부분 array[2]등등과. 제 인수 문자열 값 fieldsep는 분할 위치를 설명하는 정규 표현식 인 문자열 (만큼 FS가 입력 레코드를 분할하는 위치를 설명하는 정규식 될 수있다). 경우 fieldsep은 생략 값 FS가 사용된다. split()작성된 요소 수를 반환합니다. sepsgawk확장이며, seps[i]사이에 구분자 문자열이 있습니다.array[i]그리고 array[i+1]. 경우 fieldsep은 단일 공간은 다음 선행 공백이 들어가는 seps[0]내로 진행 공백 후행는 seps[n]여기서 N 의 리턴 값 split()(즉, 배열의 요소 수).


그냥 일반 awk가 아닌 gnu awk를 사용한다고 언급하십시오. (seps []에 구분 기호를 저장하지 않으며 다른 제한이 있습니다)
Olivier Dulac

17

좀 더 구체적으로 말씀해주세요! "작동하지 않는다"는 무슨 뜻입니까? 정확한 출력 (또는 오류 메시지), OS 및 awk 버전을 게시하십시오.

% awk -F\| '{
  for (i = 0; ++i <= NF;)
    print i, $i
  }' <<<'12|23|11'
1 12
2 23
3 11

또는 split을 사용하십시오.

% awk '{
  n = split($0, t, "|")
  for (i = 0; ++i <= n;)
    print i, t[i]
  }' <<<'12|23|11'
1 12
2 23
3 11

편집 : Solaris 에서는 4000 필드를 올바르게 처리 하려면 POSIX awk ( / usr / xpg4 / bin / awk )를 사용해야 합니다.


for(i = 0또는 for(i = 1?
PiotrNycz

i ++가 아닌 ++ i를 사용하기 때문에 i = 0입니다.
Dimitre Radoulov

3
좋아-나는 이것을 눈치 채지 못했다. 나는 더 읽기 쉬운 것이 될 것이라고 믿습니다 for (i = 1; i <= n; ++i).
PiotrNycz

5

echo "..." | awk ...불필요 fork하고 exec시스템 호출을 호출하므로 솔루션이 마음에 들지 않습니다 .

약간의 왜곡으로 Dimitre의 솔루션을 선호합니다.

awk -F\| '{print $3 $2 $1}' <<<'12|23|11'

또는 조금 더 짧은 버전 :

awk -F\| '$0=$3 $2 $1' <<<'12|23|11'

이 경우 출력 레코드가 합쳐진 실제 조건이므로 인쇄됩니다.

이 특정한 경우에 stdin리디렉션은 내부 변수 :

awk -v T='12|23|11' 'BEGIN{split(T,a,"|");print a[3] a[2] a[1]}'

나는 사용했다 꽤 오래되었지만 내부 문자열 조작으로 관리 할 수 ​​있습니다. 첫 번째 경우 원래 문자열은 내부 터미네이터로 분할됩니다. 두 번째 경우 문자열에는 항상 하나의 문자 구분 기호로 구분 된 숫자 쌍이 포함되어 있다고 가정합니다.

T='12|23|11';echo -n ${T##*|};T=${T%|*};echo ${T#*|}${T%|*}
T='12|23|11';echo ${T:6}${T:3:2}${T:0:2}

모든 경우의 결과는

112312

나는 주어진 인쇄 출력 예제에 관계없이 최종 결과가 awk 배열 변수 참조라고 생각합니다. 그러나 최종 결과를 제공하기 위해 정말 쉬운 배쉬 케이스를 놓쳤습니다. T = '12 : 23 : 11 '; echo $ {T // :}
Daniel Liston

@DanielListon 당신이 맞아요! 감사! 나는이 bash표현 에 후행 /이 남을 수 있다는 것을 몰랐다 ...
TrueY

4

실제로 awk'Input Field Separator Variable' 링크 라는 기능이 있습니다. 이것을 사용하는 방법입니다. 실제로 배열은 아니지만 내부 $ 변수를 사용합니다. 간단한 문자열을 나누는 것이 더 쉽습니다.

echo "12|23|11" | awk 'BEGIN {FS="|";} { print $1, $2, $3 }'



1

농담? :)

어때요? echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'

이것은 내 출력입니다.

p2> echo "12|23|11" | awk '{split($0,a,"|"); print a[3] a[2] a[1]}'
112312

결국에는 효과가 있다고 생각합니다 ..


문자열의 길이 때문입니까? 내 문자열 길이는 4000입니다. 어떤 아이디어
Mohamed Saligh

1

나는 이것이 일종의 오래된 질문이라는 것을 알고 있지만 내 트릭과 같은 누군가를 생각했습니다. 특히이 솔루션은 특정 수의 항목으로 제한되지 않기 때문입니다.

# Convert to an array
_ITEMS=($(echo "12|23|11" | tr '|' '\n'))

# Output array items
for _ITEM in "${_ITEMS[@]}"; do
  echo "Item: ${_ITEM}"
done

출력은 다음과 같습니다.

Item: 12
Item: 23
Item: 11
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.