변수에 전달된 디렉토리에 대한 출력을 제공하지 않는 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}"/*중괄호 확장은 마지막 토큰을 and 로 바꿉니다 "${line}"/.*.
  • /home/user/*변수 확장은 위의 내용을 and 로 바꾸고 /home/user/.*,
  • 경로 이름 확장은 위의 내용을 파일 이름 목록으로 바꿉니다.

하지만, 당신이 말할 때

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

그 다음에

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

그러면 버팀대 확장이 발생하기에는 너무 늦습니다.  grep말 그대로 이라는 파일을 찾습니다 /home/user/{*,.*}.


추신

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

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

PPS 모든 교정기가 필요하지는 않습니다.

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

괜찮을 것입니다.

답변2

전체 시스템에 대해 반복할 때 grep이 중단되는 이유는 데이터 양을 감당할 수 없어서가 아니라 /proc, /sys 또는 /dev에 있는 하나 또는 다른 의사 또는 장치 파일을 넘어갔기 때문일 가능성이 높습니다. --exclude명령줄의 옵션을 사용하여 문제가 있는 디렉터리를 제외할 수 있습니다 .

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

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

이것을 변경하면 아마도 확장하는 데 도움이 될 것입니다.

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

이를 달성하는 또 다른 방법(귀하를 대신하여 적은 수의 스크립팅 사용)은 처리를 위해 find파일 경로를 사용하고 파이핑하는 파일을 선택하는 것입니다.xargsfind / ... -print 0 | xargs -0 ...

그러나 어느 쪽이든 제외하지 않는 한 원래 재귀 grep이 넘어간 파일은 여전히 ​​넘어갈 것입니다.

관련 정보