텍스트 파일이 있습니다열.txt아래와 같이 두 개의 열이 있습니다.
1 1.1
2 4.0
3 3.2
start newset
1 2.2
2 6.1
3 10.3
4 2.1
start newset
1 18.2
2 4.3
다음과 같은 경우 새 열 쌍을 생성하려면 이를 여러 열로 변환해야 합니다.뉴스 수집 시작도착했다. 그래서 내가 원하는 출력 텍스트 파일은 다음과 같습니다. (문자열이 있는 줄을 삭제하고 싶습니다.뉴스 수집 시작):
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
답변1
이것을 시도해 볼 수 있습니다.
awk '
/^start newset/ {
max = max>i ? max : i
i = 0
set++
next
}
{
++i
a[i][set] = $0
}
END {
for( i=1 ; i<=max ; i++ ) {
for( j=1 ; j<=set ; j++ )
b = b OFS a[i][j]
sub( "\t" , "" , b )
print b
b=""
}
}
' set=1 OFS='\t' column.txt
답변2
csplit 및 붙여넣기
csplit
패턴에 따라 파일을 여러 파일로 분할하는 데 사용됩니다 . 그런 다음 paste
.
awk 'NF' column.txt | csplit --suppress-matched -s -z -f INTERIM -n 4 - '/start newset/' '{*}' ; paste INTERIM* | expand -t 6,13 ; rm -f INTERIM*
명확성을 위해 동일한 코드를 다시 형식화했습니다.
awk 'NF' column.txt | \
csplit --suppress-matched -s -z -f INTERIM -n 4 - '/start newset/' '{*}' ;
paste INTERIM* | \
expand -t 6,13 ;
rm -f INTERIM*
설명하다:
awk 'NF' column.txt
빈 줄을 제거하세요. 그렇지 않으면 입력 파일의 빈 줄이 출력에 추가 열 구분 기호를 배치합니다.- 분할
--suppress-matched
출력에 분할 패턴이 포함된 행을 포함하지 마십시오.-s
출력 파일에 대한 요약 정보를 표시하지 않습니다.-z
빈 출력 파일을 생성하지 마십시오(즉, 입력 파일의 인접한 두 줄에 분할 패턴이 포함된 경우).-f INTERIM
분할 파일의 파일 이름은 이 문자열로 시작됩니다.-n 4
분할된 파일의 파일 이름은 이 숫자를 포함하는 숫자로 끝납니다.-
STDIN
먼저 입력 파일을 실행하므로 에서 입력을 가져옵니다awk
.'/start newset/'
이 정규식을 포함하는 첫 번째 줄에서 입력 파일을 분할합니다.'{*}'
해당 정규식이 포함된 각 추가 줄에서 입력 파일을 계속 분할합니다.
paste INTERIM*
임시 파일을 추가합니다.expand -t 6,13
연결된 파일 사이의 열 간격을 조정합니다(예: 두 번째 파일은 열 6에서 시작하고 세 번째 파일은 열 13에서 시작).rm -f INTERIM*
임시 파일을 삭제합니다.
입력 파일 예 column.txt
:
1 1.1
2 4.0
3 3.2
start newset
1 2.2
2 6.1
3 10.3
4 2.1
start newset
1 18.2
2 4.3
출력 예:
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
입력 파일의 줄과 최종 출력의 줄을 들여쓰면 좀 더 복잡해집니다.
입력 파일 예 column.txt
:
1 1.1
2 4.0
3 3.2
start newset
1 2.2
2 6.1
3 10.3
4 2.1
start newset
1 18.2
2 4.3
- 추가 처리 전에 들여쓰기를 제거하려면
awk 'NF'
로 변경하세요 .awk 'NF { sub(/^ +/,"",$0) ; print $0 }'
- 들여쓰기된 출력
expand -t 6,13
으로 변경합니다 .awk '{ print " " $0 }' | expand -t 8,15
출력 예:
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
답변3
일부 임시 파일을 통한 라우팅:
$ awk 'BEGIN { n = 1 } /^start newset/ { n++; next } { name = sprintf("tmp-%04d", n); print >name }' file
이렇게 하면 터미널에 출력이 생성되지 않지만 1보다 크거나 같은 0으로 채워진 4자리 정수라는 tmp-n
이름 의 파일이 생성됩니다. n
각 데이터 세트마다 하나의 파일이 있습니다.
그런 다음 이러한 임시 파일을 함께 붙여넣을 수 있습니다.
$ paste tmp-*
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
또는 탭 대신 공백을 구분 기호로 사용하세요.
$ paste -d ' ' tmp-*
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
만약 있다면큰데이터의 세트 수에 따라 두 가지 문제가 발생합니다.
두 번째 코드 블록을
awk
변경하면 이를 방지할 수 있습니다 .awk
{ name = sprintf("tmp-%04d", n); print >name }
도착하다
{ name = sprintf("tmp-%06d", n); print >>name; close(name) }
(또한 더 큰 숫자를 허용하도록 형식 문자열 변경에 유의하세요.)
paste
패턴이tmp-*
너무 많은 파일로 확장되므로 명령을 실행하는 데 문제가 있을 수 있습니다. 이것이 문제인지 알려주시면 수정하겠습니다(파일의 열을 추가하여 결과를 작성하는 쉘 루프가 발생합니다tmp-*
).
답변4
$ awk '$1+0>=1{a[$1]=a[$1]" "$0}END{for (i in a)print a[i]}' file.txt
1 1.1 1 2.2 1 18.2
2 4.0 2 6.1 2 4.3
3 3.2 3 10.3
4 2.1
위의 awk 명령은 a라는 배열을 생성하고 첫 번째 열을 기준으로 값을 저장/추가합니다. 파일을 완전히 읽은 후에는 배열 값을 인쇄하면 됩니다.
step 1 : a[1] = "1 1.1"
step 2 : a[2] = "2 4.0"
step 3 : a[3] = "3 3.2"
step 4 : ignore the line # 4. because the first column is not numeric
step 5 : a[1] = "1 1.1 1 2.2"
step 6 : a[2] = "2 4.0 2 6.1".
....
...
once the file is fully procssed by awk, then just print the array values a[1],a[2],a[3]...a[n]