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|uniqcat파일 목록에서.
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.