열을 기반으로 파일 파티션 나누기

열을 기반으로 파일 파티션 나누기

다음 데이터 세트가 있습니다.

M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567
M8  2   22224
M9  2   55566
M10 2   4567
M11 3   44242
M12 3   234234
M13 4   2233
M14 4   2442
M15 4   322352
M16 4   235242
M17 4   2324524
M18 5   232342
M19 6   2322523
M20 6   2332523

두 번째 열의 값을 기반으로 배열을 만들고 싶습니다. 1두 번째 열의 모든 행에 다른 명령을 적용하고, 두 2번째 열의 행에 다른 명령을 적용하고, 다른 파일에 저장하고 싶은데 어떻게 해야 할지 모르겠습니다. while명령을 사용해 보았지만  모든 시도가 실패했습니다.

이 코드의 출력은 배열의 각 인덱스에 있는 원본 파일의 하위 집합이어야 합니다. 예를 들면 다음과 같습니다.

인덱스1

M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567

indexi2

M8  2   22224
M9  2   55566
M10 2   4567

등등

인덱스 i6

M19 6   2322523
M20 6   2332523

이 인덱스에 다른 명령을 적용하고 싶습니다.

쉘 스크립트 및/또는 awk에서 이 작업을 어떻게 수행합니까?

답변1

awk에서 최상의 결과를 얻을 수 있습니다.

awk '{ print > "index i"$2 }' < input

셸에서만 이 작업을 수행할 수도 있습니다.

while read a b c
do
        printf '%s\n' "$a $b $c" >> "index i$b"
done < input

awk 솔루션에는 다음과 같은 장점이 있습니다.

  • 기존 파일을 덮어쓰게 됩니다. 쉘 스크립트는 기존 파일에 추가됩니다. (이것이 당신이 원하는 것일 수도 있다고 생각합니다. 그럴 경우 awk 스크립트 >>대신 를 사용하여 수행할 수 있습니다 .)>
  • awk 스크립트는 입력 파일 간격을 유지합니다. 쉘 스크립트는 여러 공백을 단일 공백으로 줄입니다.
  • 대용량 데이터 파일의 경우 awk 스크립트가 약간 더 빠를 수 있습니다.

답변2

G-Man의 답변에 추가 :예, sh만 사용하면 똑같은 결과를 얻을 수 있습니다.(이것은 중복 질문의 사양이므로거기, G-Man이 답변하기 9시간 전에 답변했습니다.)

등에 값을 할당 set할 수 있는 기능이 내장되어 있습니다 . 다음은 bash 매뉴얼 페이지의 인용문입니다(sh에도 적용됩니다).$1 $2$3

설정[{-options|+options|--}] 인수...

set 명령의 세 번째 용도는 쉘의 위치 매개변수 값을 지정된 args로 설정하는 것입니다. 옵션을 변경하지 않고 위치 매개변수를 변경하려면 설정할 첫 번째 매개변수로 "--"를 사용하십시오. args가 없으면 set 명령은 모든 위치 인수를 지웁니다("shift $#" 실행과 동일).

그래서 우리는 이렇게 할 수 있습니다:

set -f
while read ln; do
    set -- $ln
    printf '%s\n' "$ln" >> "index i"$2
done < input
set +f

에서는 필드로 나누어 set -- $ln지며 $ln, n번째 필드는 n번째 위치 매개변수에 할당됩니다.

다음 줄의 따옴표는 $ln내용의 무결성(간격 유지 등)을 보장합니다.

* 및 ?와 같은 와일드카드 문자를 방지 set -f합니다 . set +f파일이 복잡해지지 않도록 하세요 set. 이 질문을 제기한 Scott에게 감사드립니다.

대신 printf원래는 을 사용했는데 echoScott의 두 번째 댓글( echo상대방이 로 줄을 바꾸면 혼란스러울 수 있음) 덕분에 이를 대신 사용하곤 했습니다.-n-eechoprintf

이는 sh가 이러한 유형의 작업에 적합하지 않을 수 있음을 시사합니다. 최소한 정규식을 지원하는 bash를 사용하십시오. 하지만 노력하면 가능합니다.

awk의 경우 "약간 빠르다"는 것이 아니라 디스크 IO를 고려하지 않으면 훨씬 더 빠릅니다. 따라서 먼저 awk를 사용하십시오.

그건 그렇고, "두 개의 답이 하나가 너무 많으면 두 개의 질문이 둘이 너무 많다"는 말을 들어 본 적이 없을 것입니다.

내가 방금 말했으니까 ;)

하지만 다음번에는 선택을 하고 계속해서 집중할 수 있도록 하세요.

답변3

주문하다

  for i in `awk '{if(!seen[$2]++)print $2}' y.txt`;do awk -v i="$i" 'BEGIN {print "index i"i}$2==i {print $0}END {print "========================================"}' y.txt; done

산출

index i1
M1  1   1233
M2  1   3212
M3  1   55323
M4  1   4444233
M5  1   23444
M6  1   555333
M7  1   55567
========================================
index i2
M8  2   22224
M9  2   55566
M10 2   4567
========================================
index i3
M11 3   44242
M12 3   234234
========================================
index i4
M13 4   2233
M14 4   2442
M15 4   322352
M16 4   235242
M17 4   2324524
========================================
index i5
M18 5   232342
========================================
index i6
M19 6   2322523
M20 6   2332523
========================================

관련 정보