find를 사용하여 찾은 파일의 내용을 단일 파일로 분류하려면 어떻게해야합니까?


11

귀중한 데이터를 보유한 파티션을 재 포맷하여 문제가있는 부분 (실제로 나쁜 부분)을 직접 촬영했습니다. 물론 의도적이지는 않았지만 일어났습니다.

그러나 대부분의 데이터 를 사용 testdisk하고 photorec복구했습니다. 이제 모든 데이터가 거의 25,000 개의 디렉토리에 분산되어 있습니다. 대부분의 파일은 .txt 파일이고 나머지는 이미지 파일입니다. 각 디렉토리에는 300 개가 넘는 .txt 파일이 있습니다.

나는 수 grep사용하거나 find파일로 .txt 인 파일과 출력을 특정 문자열을 추출 할 수 있습니다. 예를 들어, 다음은 데이터가 복구 된 파일에 있는지 확인하는 데 사용한 줄입니다.

find ./recup*/ -name '*.txt' -print | xargs grep -i "searchPattern"

"searchPattern"을 파일로 출력 할 수는 있지만 그 패턴 만 알려줍니다. 내가 정말로 성취하고 싶은 것은 다음과 같습니다.

모든 파일을 살펴보고 특정 문자열을 찾으십시오. 해당 문자열이 파일에서 발견되면 해당 파일의 모든 내용을 출력 파일로 분류하십시오. 패턴이 둘 이상의 파일에서 발견되면 후속 파일의 내용을 해당 출력 파일에 추가하십시오. 검색하려는 패턴을 출력하고 싶지는 않지만 패턴이있는 파일의 모든 내용을 출력하고 싶습니다.

나는 이것이 가능하다고 생각하지만 파일에서 특정 패턴을 잡은 후 파일의 모든 내용을 얻는 방법을 모른다.


제공 한 명령을 사용하면 찾고있는 결과를 얻을 수 있지만 출력을 텍스트 파일로 리디렉션하려고합니까?
— ryekayo

내 질문을 읽은 후에 "Go through ..."로 시작하는 단락은 유사 코드처럼 들립니다. 아마도 몇 줄의 for / if Python 코드로 코드를 얻을 수 있습니다. 좀 더 현명한 답변을 기다리는 동안 기회를 줄 것입니다
— Ami

확실히 psuedocode이며, bash에서도 그렇게 할 수있는 방법을 찾을 수 있습니다.
— ryekayo

@ryekayo, 그렇습니다. 출력을 제공하지만 특정 유형의 데이터가 어떤 파일에 있는지 찾아서 더 많은 데이터가 해당 파일에 있음을 알려줍니다. 그래서 그 파일의 모든 것을 잡고 다른 파일에 쓰고 싶습니다.
— Ami

if 명령의 경우 또는 if 문의 결과를 기반으로 내용을 제거 할 수있는 함수를 호출 할 수있는 스위치 케이스 또는 심지어는 if 문으로 해당 명령을 래핑 할 수 있습니다.
— ryekayo

답변:


10

목표를 올바르게 이해하면 다음이 원하는 것을 수행합니다.

find ./recup*/ -name '*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

*.txt파일의 모든 파일을 찾고 파일 과 일치하는 경우 ./recup*/각 파일을 테스트 합니다. 모든 ed 파일 의 출력은 로 보내집니다 .searchPatterncatcatoutputfile.txt

각 패턴 및 출력 파일에 대해 반복하십시오.


일치하는 디렉토리가 매우 많으면로 ./recup*끝날 수 있습니다 argument list too long error. 이 문제를 해결하는 간단한 방법은 다음과 같이하는 것입니다.

find ./ -mindepth 2 -path './recup*.txt' -exec grep -qi "searchPattern" {} \; -exec cat {} \; > outputfile.txt

이것은 전체 경로와 일치합니다. 그래서 ./recup01234/foo/bar.txt일치한다. 는 -mindepth 2일치하지 않도록이다 ./recup.txt, 또는 ./recup0.txt.


네, 그렇게 할 것이라고 생각합니다. 그리고 그것은 일할 수있는 기반을 제공합니다. 여러 문자열을 검색 할 예정이므로 여러 elif가있는 for / if 비트 코드가 작업을 자동화하는 데 도움이 될 것이라고 생각합니다. 감사합니다
— Ami

내가 생각했던 것보다 훨씬
— 나아요

작동하지 않는 것 같습니다. "/ usr / bin / find를 실행할 수 없습니다 : 인수 목록이 너무 깁니다"
— Ami

@Ami는 해당 문제에 대한 해결책을 제공하기 위해 답변을 업데이트했습니다.
— 패트릭

2
여러 문자열을 사용하는 경우 @Ami, 그냥 다른 파일 (모든 긍정적 인 파일 이름을 저장하는 것이 더 간단 수 있습니다 grep -l다음,) |sort|uniq및 cat파일 목록에서.
— Sparhawk

3

패턴을 출력하는 대신 grep에서 "-l"을 사용하여 파일 이름을 출력 한 다음 cat의 입력으로 사용하십시오.

find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern" | xargs cat

또는

cat $( find ./recup*/ -name '*.txt' -print | xargs grep -li "searchPattern")

나머지 세부 정보를 입력 할 수있을 것 같습니다. BTW, 파일 이름에 공백이나 다른 홀수 문자가있을 수있는 경우 (이 경우는 아니지만 향후 목적으로) 찾기에 -print0을 사용하고 grep에 -Z를 사용하고 xargs의 -0 옵션을 사용하여 사용하십시오 줄 바꿈이 아닌 파일 이름 사이의 null 바이트입니다.

find ./recup*/ -name '*.txt' -print0 | xargs -0 grep -Zli "searchPattern" | xargs -0 cat

2
또한 Patrick의 "two -exec"옵션을 좋아하지만 모든 파일에 대해 새 포크 (well, clone ()) 및 exec가 발생한다는 점만 다릅니다. 일반적으로 당신은 그 문제를 피하기 \+보다는 오히려 사용할 수 \;있지만, 그것이 한 쌍의 -exec args와 어떻게 작동하는지 모르겠다 ( "나쁘게"의심된다). 한 쌍의 xargs를 사용하면 몇 개의 새로운 프로세스 만 생성되며 많은 파일에서 더 빠릅니다.
— dannysauer

이것도 좋아 보인다. 감사. 하나의 멍청한 질문 : 마지막 xargs 뒤의 고양이가 파일로 출력되어야합니다.
— Ami

처음 읽었을 때 파일의 내용이 어디로 가야하는지에 대한 질문은 생각하지 않았습니다. 이 세 가지 명령은 모두 파일 내용을 STDOUT에 넣기 때문에 (끝까지) >afile또는 |acommand상황에 적합한 것을 추가하면 됩니다. :)
— dannysauer

좋은 답변을, 나는 고양이 위해서는 pg_hba.conf에 필요한 sudo find /* -name pg_hba.conf | xargs sudo cat
— 응용 프로그램 작업을

이것은 약간의 주제가 아니지만, sudo xargs대신에 사용 하는 것을 선호합니다 xargs sudo. 실행 xargs sudo하면 명령이이라고 가정하고 명령 행을 빌드합니다 sudo cat args. 그러나 cat은 / bin에 있으므로 sudo runs /bin/cat args. 명령이 / usr / local / bin과 같은 더 긴 디렉토리에있는 경우 sudo 명령이 실제로 실행되면 명령 행이 너무 길어 추적하기 어려운 오류가 발생할 수 있습니다. 또한 sudo xargsxargs를 실행했다는 기록 만하고 xargs sudo모든 인수와 함께 명령 을 기록하면 sudo 로그 줄이 길어집니다. :)
— dannysauer

1

이것은 최적의 코드는 아니지만 매우 간단하며 효율성이 문제가되지 않으면 제대로 작동합니다. 문제는 파일에서 이미 문자열을 찾았더라도 파일을 여러 번 통과시키는 것입니다.

먼저 문자열을 검색하고 일치하는 파일을 목록에 씁니다.

find ./recup*/ -name '*.txt' -execdir grep -il "searchPattern" {} >> /tmp/file_list \;

searchPattern필요에 따라 교체하면서이 단계를 반복 하십시오. 에 일치하는 파일 목록이 생성됩니다 /tmp/file_list.

문제는이 파일에 중복 된 파일이있을 수 있다는 것입니다. 따라서 복제본을로 대체 할 수 있습니다 |sort|uniq. sort그 때문에 일부는 서로 인접한 중복 배치 uniq를 제거 할 수 있습니다. 그런 다음 각 파일 이름을 개행 문자로 구분 cat하여 이러한 파일을 함께 사용할 수 있습니다 . 그 후,xargs\n

</tmp/file_list sort | uniq | xargs -d "\n" cat > final_file.txt

다른 답변과 달리 여기에는 두 단계와 임시 파일이 있으므로 여러 패턴을 찾은 경우에만 권장합니다.


0

쉘과 환경에 따라 다음과 같이 할 수 있습니다 (bash)

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1\|searchPattern2\|searchPattern3' "$file"; then
    cat "$file" >> some/other/file
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

패턴에 따라 결과를 분리하려면 다음과 같이 수정하십시오.

while IFS= read -r -d '' file; do
  if grep -qim1 'searchPattern1' "$file"; then
    cat "$file" >> some/other/file1
  elif grep -qim1 'searchPattern2' "$file"; then
    cat "$file" >> some/other/file2
  elif grep -qim1 'searchPattern3' "$file"; then
    cat "$file" >> some/other/file3
  fi
done < <(find ./recup*/ -name '*.txt' -print0)

"완료"이후의 비트는 무엇을합니까? 필자가 실제로 원하는 것은 if 블록을 수정하여 일치하는 패턴을 포함하는 파일이 다른 파일에 기록되도록하는 것입니다.
— Ami

발견 된 '.txt'파일 만 나열하며 각 파일은 null 문자로 끝납니다 (공백 및 기타 문자가 포함 된 파일 이름에 안전합니다). while루프는 그 목록을 읽고 않습니다 grep/ 조건 cat부분.
— steeldriver

코드를 실행하려고하면 다음과 같은 오류가 발생합니다. ./recoverData.sh : 구문 오류 : "("예기치 않은. find 명령 주위의 괄호에서 나옵니다.
— Ami

어떤 쉘을 사용하고 있습니까? 프로세스 대체 구문은 bash에만 적용됩니다. 따라서 "자격과 환경에 따라"자격이 있습니다
— steeldriver

1
당신도 대화 형 bash 쉘에서 직접 명령 (들)을 실행하거나 그 첫번째 라인 오두막을 포함하는 파일에 넣을 수 #!/bin/bash와 그것을 실행하게 chmod +x recoverData.sh하고, 사용하여 실행합니다 ./recoverData.sh. 마십시오 하지 사용 sh recoverData.sh하기 때문에 /bin/sh가능성이있다 dash쉘 .
— steeldriver
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.