sed를 사용한 텍스트 조작


12

현재 다음과 같은 내용을 가진 여러 개의 텍스트 파일이 있습니다 (여러 줄이 있음).

565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

각 줄을 다음 형식으로 변경하고 싶습니다.

0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

sed를 사용하여 위의 작업을 수행하는 방법이 있습니까? 아니면 파이썬에 의지해야합니까?

답변:


22

sed로 할 수는 있지만 다른 도구는 더 간단합니다. 예를 들면 다음과 같습니다.

$ awk '{
        printf "%s ", $2; 
        for(i=3;i<=NF;i++){
            printf "%s:%s:1 ",$1,$(i) 
        }
        print ""
       }' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

설명

AWK는 각 필드를 저장 (기본적으로) 공백에 입력의 각 행을 분할한다 $1, $2, $N. 그래서:

  • printf "%s ", $2; 두 번째 필드와 후행 공백을 인쇄합니다.
  • for(i=3;i<=NF;i++){ printf "%s:%s:1 ",$1,$(i) }: 필드 3을 마지막 필드 (필드 수)로 반복하고 NF각 필드에 대해 첫 번째 필드, a :, 현재 필드 및 a를 인쇄합니다 :1.
  • print "" : 이것은 마지막 줄 바꿈을 인쇄합니다.

또는 Perl :

$ perl -ane 'print "$F[1] "; print "$F[0]:$_:1 " for @F[2..$#F]; print "\n"' file 
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1 

설명

-a차종은 perl같이 행동 awk하고 공백에 입력을 분할합니다. 여기서 필드는 배열에 저장됩니다. @F즉, 첫 번째 필드는 $F[0]두 번째 $F[1]등이됩니다.

  • print "$F[1] " : 두 번째 필드를 인쇄합니다.
  • print "$F[0]:$_:1 " for @F[2..$#F];: 필드 3을 마지막 필드까지 반복합니다 ( $#F배열의 요소 수 @F이므로 @F[2..$#F]배열이 끝날 때까지 세 번째 요소부터 시작하여 배열 슬라이스가 발생 함). 첫 번째 필드, a :, 현재 필드 및 a를 인쇄합니다 . :1.
  • print "\n" : 이것은 마지막 줄 바꿈을 인쇄합니다.

12

여기는 끔찍한 sed 방법!

$ sed -r 's/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/; :a s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /; t a; s/ $//' file
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1 
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

더 읽기 쉽게 :

sed -r '
s/^([0-9]+) ([0-9]+) ([0-9]+)/\2 \1:\3:1/
:a 
s/([0-9]+)(:[0-9]+:1) ([0-9]+)( |$)/\1\2 \1:\3:1 /
t a
s/ $//'

노트

  • -r ERE 사용
  • s/old/new/교체 oldnew
  • ^([0-9]+) 줄의 시작 부분에 숫자를 저장
  • \1 처음 저장된 패턴에 대한 역 참조
  • :a 스크립트의이 섹션에 레이블을 지정하십시오. a
  • ( |$) 공백 또는 줄의 끝
  • t 마지막 교체가 성공적 이었는지 테스트합니다. 성공한 경우 다음 명령을 수행하십시오.
  • a라벨을 찾아 :a다시
  • s/ $// 후행 공백을 제거하십시오

따라서 첫 번째 부분에 구조를 추가 한 후 반복적으로 구조의 마지막 인스턴스를 찾아 다음 번호에 적용합니다 ...

그러나 나는 다른 도구가 더 쉬워진다는 데 동의합니다 ...


나는 당신의 sed 해결책을 기다리고있었습니다 : D
Ravexina

: D 시간이 좀 걸렸다 @Ravexina-나는 muru가 더 깨끗한 것을 만들 수 있다고 생각합니다
Zanna

5

awk로 :

awk '{printf "%s ",$2; for (i=3; i<=NF; i++) printf $1":"$i":1 "; printf "\n"}' file

또는 bash와 함께 :

while read -r -a a; do                  # read line to array a
  printf "%s " ${a[1]}                  # print column #1
  for ((i=2;i<${#a[@]};i++)); do        # loop from column #2 to number of columns
    printf "%s " "${a[0]}:${a[$i]}:1"   # print content/values
  done
  echo                                  # print line break
done < file                             # read file from stdin

산출:

0 565 : 10 : 1 565 : 12 : 1 565 : 23 : 1 565 : 18 : 1 565 : 17 : 1 565 : 25 : 1 
1 564 : 7 : 1 564 : 12 : 1 564 : 13 : 1 564 : 16 : 1 564 : 18 : 1 564 : 40 : 1 564 : 29 : 1 564 : 15 : 1 

5

글쎄, 당신은 sed에서 할 수 있지만 파이썬도 작동합니다.

$ ./reformatfile.py  input.txt                                                                        
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1

내용은 다음 reformatfile.py과 같습니다.

#!/usr/bin/env python3
import sys

with open(sys.argv[1]) as fd:
    for line in fd:
        words = line.strip().split()
        pref = words[0]
        print(words[1],end=" ")
        new_words = [ ":".join([pref,i,"1"]) for i in words[2:] ]
        print(" ".join(new_words))

어떻게 작동합니까? 특별히 특별한 일은 없습니다. 첫 번째 명령 줄 인수를 파일로 읽고 각 줄을 "단어"또는 개별 항목으로 나눕니다. 첫번째 단어는 pref가변적 이되고 , 공백으로 끝나는 stdout second (words [1]) 항목에 인쇄합니다. 다음으로리스트 이해를 통해 새로운 "단어"세트를 구성 .join()하고 임시 pref, 각 단어 및 string리스트에서 기능합니다 "1". 마지막 단계는 그것들을 출력하는 것입니다


4

awk:

awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i);\
          printf("%s:%s:1\n", $1, $NF)}' file.txt

공백으로 구분 된 필드를 원하는 형식으로 형식화하는 것이 중요합니다.

  • printf("%s ", $2) 후행 공백으로 두 번째 필드를 인쇄합니다.

  • for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i) 마지막 3 ~ 2 번째 필드를 반복하여 원하는 형식 (첫 번째 필드, 콜론, 현재 필드, 콜론, 마지막으로 1)으로 후행 공백으로 필드를 인쇄합니다.

  • printf("%s:%s:1\n", $1, $NF) 줄 바꿈으로 마지막 필드를 인쇄합니다

예:

% cat file.txt
565 0 10 12 23 18 17 25
564 1 7 12 13 16 18 40 29 15

% awk '{printf("%s ", $2); for(i=3; i<NF; i++) printf("%s:%s:1 ", $1, $i); printf("%s:%s:1\n", $1, $NF)}' file.txt
0 565:10:1 565:12:1 565:23:1 565:18:1 565:17:1 565:25:1
1 564:7:1 564:12:1 564:13:1 564:16:1 564:18:1 564:40:1 564:29:1 564:15:1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.