각 파일의 텍스트를 필터링하고 쉼표로 구분된 값 목록으로 변환합니다.

각 파일의 텍스트를 필터링하고 쉼표로 구분된 값 목록으로 변환합니다.

여러 파일에서 일부 정보를 추출하고 csv 유형 파일을 만들려고 합니다. 지금까지 파일의 일부를 추출하고 작성했지만 각 출력 사이에 쉼표를 추가하거나 끝에서 개행을 제거하는 방법을 모릅니다.

#!/bin/bash
for file in folder/*.txt do
  grep 'sometext:' $file | sed '/^.*:\s*//' >> list.txt
  #doing simliar stuff with other lines in the current file
done

개행 제거를 사용해 보았지만 echo -n유용한 정보가 반환되지 않았습니다.

코드의 역할:
폴더의 각 파일에 대해 일부 패턴(예: 등)으로 시작하는 줄을 찾아 sometext:나머지 someothertext:줄과 a ,list.txt.

폴더에 있는 파일 콘텐츠의 예:

randomtext: ...
sometext: Hello
randomtext: ...
someothertext: World
somedifferenttext: !
randomtext:

출력 파일에 한 줄이 생성됩니다.Hello,World,!,

답변1

글쎄요, 처음부터 루프를 사용하지 마세요 for! 이는 매우 비효율적입니다. grep모든 파일 이름을 한 번에 지정하십시오 .

grep 'sometext:' folder/*.txt

그러나 이 경우에는 awk대신 를 사용하여 grep테스트하기 위해 입력 파일의 10개 복사본을 만들었습니다.

$ awk '{
        if($1~/sometext|someothertext|somedifferenttext/){
            printf "%s,",$2
        }
        if(FNR==1 && NR>1){
            print ""
        }
    }
    END{ print "" }' folder/*txt 
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,

설명하다

awk입력을 한 줄씩 읽고 여백 -F(기본적으로 변경할 수 있음)의 각 줄을 필드로 분할하는 스크립팅 언어입니다. 첫 번째 필드는 이고 $1, 두 번째 필드는 $2이런 식입니다.

  • if($1~/sometext|someothertext|somedifferenttext/){: 첫 번째 필드가 sometextor someothertext또는 와 일치하는 경우 somedifferenttext. 이 항목도 일치합니다 foosometext. 정확한 일치를 제한하려면 다음과 같이 변경하세요.

    if($1=="sometext:" || $1=="someothertext:" || $1=="somedifferenttext:"){
    
  • printf "%s,",$2: 위의 조건이 충족되면 두 번째 필드를 인쇄하고 그 뒤에 쉼표를 입력합니다.

  • if(FNR==1 && NR>1){ print "" }: NR현재 입력 줄 번호와 FNR현재 파일의 줄 번호입니다. 따라서 파일에 줄 번호 1이 있을 때마다 줄 바꿈이 인쇄됩니다( printawk 호출은 기본적으로 줄 바꿈을 추가하므로 아무것도 인쇄하지 않는 것은 줄 바꿈을 인쇄하는 것과 같습니다). 그러나 처리된 총 줄 수도 1이면 원합니다. 티. 즉, 새 파일을 읽기 시작할 때마다 개행 문자가 인쇄됩니다.

  • END{ print "" }': 모든 파일을 처리한 후 개행 문자도 인쇄합니다.

이는 행당 2개의 필드만 있다고 가정합니다. 전체 행을 인쇄해야 하는 경우 다음을 사용할 수 있습니다(정확한 일치만 인쇄하는 버전으로 설명됨).

awk '{
    if($1=="sometext:" || 
       $1=="someothertext:" || 
       $1=="somedifferenttext:"){
        $1=""; 
        printf "%s,",$0
    }
    if(FNR==1 && NR>1){print ""}
    }END{print ""}' folder/*txt | sed 's/^ //'

$0차이점은 (전체 줄)을 대신 사용하고 인쇄하기 전에 빈 문자열로 $2설정한다는 것입니다 $1. 이로 인해 시작 부분에 추가 공간이 인쇄되므로(비어 있음은 여전히 ​​필드로 간주되므로) 이를 제거하기 위해 $1전달합니다 .sed


또는 Perl에서 모든 작업을 수행할 수 있습니다.

 $ perl -lane '
    if($F[0]=~/(sometext|someothertext|somedifferenttext):/){
        push @k,@F[1..$#F]
    } 
    if(eof){
        print join ",", @k; @k=();
    }' folder/file*
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!

또는 후행이 있을 수 있습니다 ,.

 $ perl -lane '
    if($F[0]=~/^(sometext|someothertext|somedifferenttext):$/){
        push @k,@F[1..$#F]
    } 
    if(eof){
        print join ",", @k , ""; @k=();
    }' folder/file*
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,

설명하다

여기서의 기본 아이디어는 동일합니다. Perl의 스위치는 각 입력 라인을 배열로 분할하는 -a것처럼 동작합니다 . 그런 다음 배열의 첫 번째 요소가 필수 문자열 중 하나이면 나머지 필드( )가 배열에 추가됩니다 . 파일의 끝( )에 도달하면 배열의 내용을 쉼표로 연결 하고 결과 문자열을 인쇄합니다.awk@F@F[1..$#F]@kif(eof)@k


마지막으로, 시도하는 방식대로 수행하는 방법이 있습니다(GNU 가정 grep).

$ for f in folder/*; do 
    grep -hoP '^(sometext|someothertext|somedifferenttext): \K.*' "$f" | 
        perl -pe 's/\n/,/; END{print "\n"}'; 
  done
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,

답변2

그리고 gnu sed:

sed -Es '/pattern1|pattern2|pattern3/{
s/.*:[[:blank:]]*//;H}
$!d;x;/^\n$/d;s/\n(.*)/\1,/;s/\n/,/g' folder/*.txt > list.txt

내용 list.txt은 다음과 유사합니다.

file1match1,file1match2,
file2match1,
file4match1,file4match2,file4match3,

file3일치하는 행이 없으므로 출력에서 ​​누락되었습니다.무늬*.
작동 방식: 각 파일을 개별적으로 처리하여 일치하는 줄에서 원하지 않는 부분을 -s제거합니다.s/.*:[[:blank:]]*//무늬*결과를 H이전 버퍼에 추가합니다. 버퍼를 변경 $하면 la t를 제외한 모든 줄이 삭제됩니다. 패턴 공간에 ewline이 하나만 x있으면 \n파일에 일치하는 줄이 없다는 의미입니다.무늬*따라서 패턴 공간이 제거됩니다. 그렇지 않으면 선행 \n줄바꿈을 제거하고 나머지를 쉼표로 바꾸고 후행 쉼표를 추가합니다.

다른 sed경우에는 다음을 반복해야 합니다.

for file in folder/*.txt do
sed '/pattern1\|pattern2\|pattern3/{
s/.*:[[:blank:]]*//
H
}
$!d
x
/^\n$/d
s/\n\(.*\)/\1,/
s/\n/,/g' "$file"
done > list.txt

관련 정보