긴 파일에서 텍스트 줄 추출

긴 파일에서 텍스트 줄 추출

다음 텍스트 파일이 있습니다.

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

각 파일을 별도의 파일로 나누고 싶습니다. 내가 정말로 필요한 것은 주석이 없는 URL을 추출하는 것뿐입니다. 주석을 보존하는 것은 선택 사항입니다. importantname1.txt 또는 .txt가 추가된 각 주석 줄 끝에 쉼표 뒤에 오는 이름과 같이 각 파일의 이름을 지정하고 싶습니다.

따라서 importantname1.txt의 내용은 다음과 같습니다.

importanttext1 

아니면 아마도

#info1 info2 info3 ,importantname1
importanttext1

따라서 행이 추출되어 주석 뒤에 파일 이름으로 저장되고 이 경우 파일 이름 importantname1.txt에 .txt가 추가됩니다.

예제 파일의 각 행 세트에 대해 이 작업을 수행해야 합니다. 주석을 보존하는 것은 중요하지 않지만 스크립트가 가능하려면 주석이 필요합니다. 또한 헤더에 알 수 없는 수의 주석 줄이 있다는 점을 고려해야 합니다. 주석 줄은 항상 각 importanttextX 줄 앞에 있습니다.

답변1

노력하다:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

샘플 입력에 적용됩니다.

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

위의 실행 후 디렉토리에 다음 파일이 있습니다.

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

새 파일의 내용은 다음과 같습니다.

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

작동 원리

Awk는 입력 파일을 한 줄씩 읽습니다. 우리 스크립트는 해당 줄을 주석 또는 비주석으로 분류합니다. 주석 라인의 경우 파일 이름과 주석이 저장됩니다. 코멘트가 없는 경우 새 파일이 생성되어 인쇄됩니다.

  • `-F,

    이는 awk에게 입력 시 필드 구분 기호로 쉼표를 사용하도록 지시합니다. 이런 방식으로 파일 이름은 항상 마지막 필드가 됩니다.

  • /^#/{f=$NF".txt";cmt=$0; next}

    줄이 로 시작하면 #마지막 필드인 $NF.txt파일 이름을 저장합니다 f. 주석 줄 전체가 cmt. 그런 다음 awk에게 나머지 명령을 건너뛰고 점프하여 해당 next줄에서 다시 시작하도록 지시합니다.

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    주석이 아닌 줄의 경우 마지막으로 본 주석 cmt과 현재 줄을 $0마지막으로 본 파일 이름에 인쇄합니다 f. 그런 다음 에 대한 파일 핸들을 닫습니다 f.

잘못된 파일 이름으로부터 보호

파일 이름으로 사용될 필드에 가 포함되어 있으면 /OS는 파일 이름을 디렉터리를 포함하는 것으로 해석합니다. 이를 방지하기 위해 다음과 같이 모두를 using /으로 바꿀 수 있습니다 .-gsub(/\//, "-", f)

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

답변2

a) 칭찬되지 않은 모든 줄과 앞의 정보 줄을 핑하고 b) 정보 주석 줄을 기준으로 출력을 분할하여 grep작업 을 수행할 수 있습니다.csplitgrep

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

-v즉 , 시작 부분에 #이 있는 줄을 추출 하지 말고 ^#그러한 줄 앞에 한 줄을 추출하십시오 -B1. 그런 다음 -줄 시작 부분의 각 #에서 들어오는 파이프 입력을 분할하고 , 빈 파일을 무시 -z하고 가능한 한 자주 수행합니다 {*}.

이름 바꾸기는 별도의 단계여야 합니다( csplit출력 이름을 xx00, xx01 ...으로 자동 지정 - -f-b옵션을 사용하여 각각 접미사와 접미사 변경).

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done

관련 정보