grep이 변수에 전달된 디렉터리에 대한 출력을 제공하지 않습니다.

grep이 변수에 전달된 디렉터리에 대한 출력을 제공하지 않습니다.

bash지정된 디렉터리 트리에 있는 파일 내용에서 지정된 하위 문자열이 있는지 검색하는 스크립트를 작성하려고 합니다 .

시스템의 디렉터리(및 모든 하위 디렉터리)를 반복해야 할 수 있으므로 재귀 함수 만으로는 grep충분하지 않으며 이로 인해 메모리 부족 및 중단이 발생할 수 있습니다. 따라서 스크립트에 전달된 매개 변수를 나타내는 다음 변수를 사용하여 지정된 디렉터리 트리의 모든 디렉터리 및 하위 디렉터리 목록을 가져오기로 결정했습니다 ./grepfind

searchdir=$HOME     # passed in a script argument
searchstr="secret"  # passed in a script argument

유틸리티를 호출 find하고 출력을 임시 파일에 저장합니다.

TF=$(mktemp)
find ${searchdir} -type d 1>$TF 2>/dev/null

while-do임시 파일의 모든 디렉터리 목록을 사용하여 각 디렉터리의 모든 파일을 검색하기 위해 루프를 사용하여 파일 줄을 계속 반복합니다 . 의 경우 grep에는 제공된 매개변수 형식을 사용합니다.이 답변숨겨진 파일을 포함하여 단일 디렉터리의 모든 파일을 검색합니다.

cat $TF | while read line || [[ -n $line ]];
do
    grepdir="${line}/{*,.*}"
    grep -sHn "${searchstr}" ${grepdir}
done

...그러나 이 코드는 출력을 생성하지 않습니다.

확인했는데...

여기에는 ${TF}모든 디렉토리의 올바른 목록이 포함되어 있습니다. 출력 ${grepdir}변수는 내가 찾을 것으로 예상되는 출력을 제공합니다.

/home/user/{*,.*}
/home/user/.ssh/{*,.*}
/home/user/test/{*,.*}
# ... and so on

하드코딩된 디렉터리, 특히 두 개의 테스트 파일과 찾아야 할 문자열이 포함된 grep이 디렉터리에서 명령을 실행하는 경우~/test/

grep -sHn "${searchstr}" /home/user/test/{*,.*}

...부분 문자열 "secret"이 포함된 두 개의 파일을 올바르게 출력합니다.

/home/user/test/asdf:7:secret
/home/user/test/test.txt:5:asdfasfdsecretaasdfafd

나에게 맞는 형식은 처음에는재귀 사용에 대한 답변grep. 내가 이렇게 하면:

cat $TF | while read line || [[ -n $line ]];
do
    grep -rn "${line}" -e "${searchstr}"
done

...일부 출력(기술적으로는 정확하지만 중복된 항목이 많음)을 얻었지만 grep디렉터리가 재귀적으로 처리되고 모든 디렉터리 목록이 있으므로 동일한 결과를 여러 번 얻을 수밖에 없으며 상황에 따라 위와 같이 루트 디렉토리는 grep완전히 실패할 것입니다. 이것이 제가 피하려고 하는 것입니다.


또한 매개변수로 전달하는 등 작동시키기 위해 수행한 해킹 $(echo "${grepdir}")도 결과가 없다는 점을 언급하고 싶습니다.

내 생각이나 이해에 오해가 있을 수도 있습니다 bash. 호출 전에 변수를 확장하면 안 되나요 bash? 내 스크립트의 어디에서 문제가 발생했나요?${grepdir}grep

답변1

규칙 #1: 명령이나 스크립트가 원하는 대로 작동하지 않을 때 오류 메시지를 확인하세요.  그것들을 던지지 마십시오  /dev/null.

다음과 유사한 오류 메시지가 나타납니다.

grep: /home/user/{*,.*}: No such file or directory
grep: /home/user/.ssh/{*,.*}: No such file or directory
grep: /home/user/test/{*,.*}: No such file or directory

하지만 당신은 그들을 볼 수 없습니다.

우리가 보면큰 타격(1), 보자

확장은 단어로 분할된 후 명령줄에서 수행됩니다. 수행되는 확장 유형에는 중괄호 확장, 물결표 확장, 매개변수 및 변수 확장, 명령 대체, 산술 확장, 토큰화, 경로 이름 확장 등 7가지 유형이 있습니다.

확장 순서는 중괄호 확장, 매개변수 및 변수 확장, 산술 확장, 명령 대체(왼쪽에서 오른쪽으로 수행됨)입니다.

귀하의 경우 중요한 부분은 중괄호 확장이 변수 확장 전에 발생한다는 것입니다. 그래서 당신이 말한다면

grep -sHn "${searchstr}" "${line}"/{*,.*}

그 다음에

  • 중괄호 확장은 마지막 토큰을 "${line}"/*및 로 바꿉니다 "${line}"/.*.
  • 변수 확장은 위의 내용을 다음으로 변환 /home/user/*합니다 /home/user/.*.
  • 경로 이름 확장은 위의 내용을 파일 이름 목록으로 변환합니다.

하지만 당신이 말할 때

grep -sHn "${searchstr}" ${grepdir}

그 다음에

  • 변수 확장은 마지막 토큰을 /home/user/{*,.*},

그러면 보조기 확장이 일어나기에는 너무 늦습니다.  grepliteral이라는 파일을 찾으세요 /home/user/{*,.*}.


폴리스티렌

grep -sHn "${searchstr}" "${line}/{*,.*}"

따옴표는 중괄호 확장 및 경로 이름 확장이 발생하는 것을 방지하기 때문에 작동하지 않습니다.

조달청: 교정기는 그렇게 많이 필요하지 않습니다.

grep -sHn "$searchstr" "$line"/{*,.*}

그게 다야.

답변2

grep이 시스템 전체에서 반복되는 동안 중단되는 이유는 아마도 많은 양의 데이터를 처리할 수 없기 때문이 아니라 /proc, /sys 또는 /dev에 있는 하나 이상의 의사 파일이나 장치 파일에서 오류가 발생하기 때문일 것입니다. . --exclude명령줄의 옵션을 사용하여 문제가 있는 디렉터리를 제외 할 수 있습니다 .

와일드카드 문자를 확장하지 않는 이유는 다음 줄에서 인용되기 때문입니다.

    grepdir="${line}/{*,.*}"

이를 변경하면 확장에 도움이 될 수 있습니다.

    grepdir="${line}/"{*,.*}

이를 달성하는 또 다른 방법(사용자를 대신하여 더 적은 스크립트 작성)은 파일 경로를 사용하여 파일을 선택 하고 처리할 find파일 경로를 전달하는 것입니다 .xargsfind / ... -print 0 | xargs -0 ...

그러나 어느 쪽이든 원래 재귀 grep이 발견한 파일을 제외하지 않는 한 여전히 발견될 수 있습니다.

관련 정보