다양한 파일에서 블록 패턴을 찾고 해당 파일에서 특정 라인을 선택적으로 추출합니다.

다양한 파일에서 블록 패턴을 찾고 해당 파일에서 특정 라인을 선택적으로 추출합니다.

나는 수만 개의 디렉토리를 가지고 있습니다. 각 디렉터리의 이름은 숫자로 지정됩니다. 예를 들어 1, 2, 3,... 각 디렉터리에는 라는 큰 .dat 파일이 포함되어 있으며 data.dat, 각 파일에는 다음과 같은 섹션이 있습니다.

Configurations for Sm:

  Sm Nd H  O 

  0  1  4  0          1.00          7.14%
  1  0  3  0          3.00          7.14%
  0  0  5  0          1.00          7.14%

각 행의 처음 두 숫자에 관심이 있습니다. 제 생각에는:

  • 로 시작하는 모든 줄(이 경우 숫자의 첫 번째 줄)은 0 1해당 줄로 시작하는 파일 이름(번호)으로 명명된 새 파일로 끝납니다. 0-1.dat아래는 "예제"라고 불리는 예입니다.
  • 마찬가지로 (여기서는 두 번째 줄)로 시작하는 모든 줄은 1 0해당 줄의 시작 부분에 있는 파일 번호로 호출되는 파일로 끝나야 합니다.1-0.dat
  • (여기서는 세 번째 줄)로 시작하는 모든 줄은 0 0이름이 지정된 줄로 이동해야 합니다 0-0.dat.

필요한 라인을 찾는 복잡성은 다음과 같습니다.

  • 경우에 따라 행 중 하나가 누락되거나 행 순서가 다를 수 있습니다.
  • 또한 각 파일에는 이라는 이름의 여러 섹션이 있습니다 Configurations for X. 여기서 X는 문자열입니다. 따라서 어떻게든 식별자를 사용 Configurations for Sm:하고 그 아래의 첫 번째 숫자 집합을 검색해야 합니다.

내가 달성하고자 하는 것의 예에서 줄의 첫 번째 숫자는 줄이 추출된 파일이 포함된 디렉터리 이름/번호입니다.

Example
In file called 0-1.txt:
1    0  1  4  0          1.00          7.14%
2    0  1  7  1          1.00          7.14%
3    0  1 ....

In file called 1-0.txt:
1    1  0  1  0          1.00          7.14%
2    1  0  4  2          1.00          7.14%
3    1  0 ....

나는 현재 다음을 가지고 있습니다:

find . -name data.dat -exec grep "Configurations for Sm:" {} + > 0-1.txt

하지만 이 모든 작업은 그 뒤에 오는 내용을 Configurations for Sm:별도의 파일에 저장하는 것뿐입니다. 내가 해야 할 일을 어떻게 해야 할지 모르겠습니다. Configurations for Sm:숫자 내용으로 아래 행을 찾으세요. 누구든지 팁이 있거나 저를 온라인 리소스로 안내해 주시면 매우 감사하겠습니다. 감사해요.

답변1

sed와 를 조합해서 사용해도 될 것 같아요 grep.

모든 디렉토리 0, 1, 2,...가 다음 위치에 있다고 가정합니다 /your/path(예 /your/path/0/data.dat: ).

for dir in /your/path/*; do
    idx=$(basename ${dir})
    sed -n '/Configurations for Sm:/,/Configurations for/p' ${dir}/data.dat | \
        grep '^ \+0 \+1' | \
        sed "s/^/${idx}/" >> "0-1.dat"
done

첫 번째는 sed파일의 흥미로운 부분(두 모드 Configurations for Sm:와 모드 사이)만 추출해야 합니다.Configurations for

grep줄의 시작 부분 과 일치합니다 0 1(가운데에 양수 공백 포함).

두 번째 sed는 줄 시작 부분에 "index"(디렉토리 이름)를 추가합니다.

>>출력은 "0-1.dat"에 추가됩니다( ).

0다양한 합계 조합을 테스트하기 위해 외부 루프를 추가할 수 있습니다 1.

참고: 나는 이것을 제대로 테스트하지 않았습니다.

답변2

awk해결책은 어떻습니까?

awk '/^ *[0-1] +[0-1]/{
    n=split(FILENAME,d,"/");print d[n-1], $0 > $1"-"$2".txt"
}' $(find . -name "*.dat")

먼저 find모든 파일을 dat제공하되 공백이 아닌 처음 2개의 문자로 awk0 또는 1로 시작하는 행만 처리합니다.^

/^ *[0-1] +[0-1]/

그런 다음 split파일 이름을 /배열에 넣고 배열의 요소 수를n

n=split(FILENAME,d,"/")

마지막으로 디렉터리 이름/번호( d[n-1]배열의 요소)와 dat파일의 데이터를 $0처음 두 값으로 구성된 파일로 인쇄합니다.

print d[n-1], $0 > $1"-"$2".txt"

수십 또는 수천 개의 파일이 있는 경우 한 줄당 오버헤드가 너무 클 split수 있습니다 FILENAME. 이 경우 각 파일을 반복하여 awk정리된 파일에 추가 할 수 있습니다.>> $1"-"$2".txt"

아마도....

find . -iname "*.dat" -print0 | xargs -0  -n 1 -P 0 awk 'NR==1{n=split(FILENAME,d,"/"); dir=d[n-1]}/ *[0-1] +[0-1]/{print dir, $0 >> $1"-"$2".txt"}'

관련 정보