파일에서 고정 간격으로 줄을 병합하는 방법은 무엇입니까?

파일에서 고정 간격으로 줄을 병합하는 방법은 무엇입니까?

파일이 있고 그 내용은 다음과 같습니다.

a1
b1
c1
aa
bb
cc
aaa
bbb
ccc
d1
e1
f1
dd
ee
ff
ddd
eee
fff
g1
h1
i1
gg
hh
ii
ggg
hhh
iii

고정 간격(이 경우 3)으로 행을 병합하고 다음과 같은 결과를 얻는 가장 좋은 방법은 무엇입니까?

a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

입력에서 출력을 얻는 알고리즘은 다음과 같습니다.

  • 먼저 우리는 a1인 행 1을 얻습니다.
  • 우리는 간격이 3이라는 것을 알고 있습니다.
  • 따라서 1행, (1+3)행, (1+3+3)행은 같은 행에 있어야 합니다.
  • 마찬가지로 2, 5, 8행은 같은 행에 있어야 합니다.

저것들a1,아아그리고아아아등은 임의의 더미 텍스트일 뿐 임의의 문자열일 수 있습니다. 요점은 사이에 고정된 간격이 있다는 것입니다.a1,아아그리고아아아.

현재 나는 이 작업을 수행하기 위해 emacs 키보드 매크로를 사용합니다. 하지만 이 문제를 해결하는 더 좋은 방법이 있는지 알고 싶습니다. 미리 감사드립니다.

답변1

/anything 에 있고 gnu행 수가 9의 배수인 경우 다음을 실행할 수 있습니다.

split -l9 --filter='pr -3 -s" " -t' infile

이렇게 하면 입력이 9개 줄로 분할되고 각 부분은 파이프로 연결되어 pr -3 -s" " -t'열이 생성됩니다. 줄의 길이와 pr옵션을 사용하여 플레이해야 할 수도 있습니다 -w. 자세한 내용은 페이지를 -l참조하세요 .man

답변2

다음은 세 줄 간격으로 세 세트를 가져오도록 하드 코딩된 awk의 단순한 솔루션입니다.

{
  if (NR > 1 && (NR % 9) == 0) {
    print a "\n" b "\n" c " " $0
    a=""
    b=""
    c=""
  } else if (NR % 3 == 1) {
    if (NR % 9 > 1) {
      a=a" "$0
    } else {
      a=$0
    }
  } else if (NR % 3 == 2) {
    if (NR % 9 > 2) {
      b=b" "$0
    } else {
      b=$0
    }
  } else {
    if (NR % 9 > 3) {
      c=c" "$0
    } else {
      c=$0
    }
  }
}

파일에 저장하고 실행해 보세요 awk -f thatfile < input. 더 똑똑한 방법이 있다고 확신하지만 매일 awk에서 일하지는 않습니다.

답변3

조금 까다 롭습니다. 나는 그것을 할 수 있는 단일 유틸리티를 모른다:

이 파이프라인은 (기본적으로) 한 번에 9줄을 읽고 pr3개 열로 형식을 지정하는 데 사용됩니다.

# there are 9 single hyphens below
paste -d: -- - - - - - - - - - < file | while read line; do
    tr : '\n' <<<"$line" | pr -s" " -T -3
done
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

이는 실제 텍스트에 콜론이 없다고 가정합니다.

답변4

매우 간단하고 명확한 방법 중 하나TXR:

@(repeat)
@x0
@x1
@x2
@y0
@y1
@y2
@z0
@z1
@z2
@  (output)
@x0 @y0 @z0
@x1 @y1 @z1
@x2 @y2 @z2
@  (end)
@(end)

달리다:

$ txr reshape.txr data
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

이를 압축하는 방법이 있지만 다음과 같이 이해하려면 조금 더 노력해야 합니다.

@(repeat)
@  (collect :times 9)
@line
@  (end)
@  (bind (x y z) @(tuples 3 line))
@  (output)
@    (repeat)
@x @y @z
@    (end)
@  (end)
@(end)

또한 Awk에서 자신이 수행하는 작업을 어느 정도 아는 사람이 구현하는 방법은 다음과 같습니다.

        { a[(NR-1)%9] = $0 }
!(NR%9) { print a[0], a[3], a[6]
          print a[1], a[4], a[7]
          print a[2], a[5], a[8] }

산출:

$ awk -f reshape.awk data
a1 aa aaa
[ ... ]
i1 ii iii

그리고 해당 코더가 반복되는 print패턴이 불쾌하다고 판단하면:

        { a[(NR-1)%9] = $0 }
!(NR%9) { for (i = 0; i < 3; i++)
            print a[i], a[i+3], a[i+6] }

TXR Lisp 솔루션:

[(opip (tuples 3) (tuples 3) (mappend transpose)
       (mapcar (aret `@1 @2 @3`)) tprint)
 (get-lines)]

달리다:

$ txr reshape.tl < data

명령줄에서: 사용 -t, 삭제 tprint:

$ txr -t '[(opip (tuples 3) (tuples 3) (mappend transpose)
                 (mapcar (aret `@1 @2 @3`)))
           (get-lines)]' < data

이는 입력을 삼중항으로 연결하는 파이프라인을 통해 입력한 다음 해당 삼중항의 삼중항(기본적으로 중첩 목록으로 구성된 3x3 행렬)으로 작동합니다. 이러한 행렬은 개별적으로 전치된 다음 해당 행이 함께 추가되어 하나의 거대한 삼중항 목록을 만듭니다. 이러한 삼중 항은 aret부분 적용 연산자와 문자열 보간법을 사용하여 문자열로 변환되고 tprint문자열 목록을 출력할 라인으로 처리하는 출력입니다. 구문

(aret `@1 @2 @3`)

비슷한 것으로 확장됩니다.

(lambda (. args)
  (apply (lambda (arg1 arg2 arg3)
           `@arg1 @arg2 @arg3`)
         args))

기본적으로 인수를 3개 인수 익명 함수에 적용할 인수 목록으로 처리하는 1개 인수 익명 함수를 암시적으로 생성합니다. 여기서 , @1@2@3인수를 나타냅니다. 함수 본문은 이러한 특수 숫자 매개변수를 기계 생성 인수 이름으로 대체하여 원래 준문자열 표현식에서 파생됩니다.

관련 정보