bash
지정된 디렉터리 트리에 있는 파일 내용에서 지정된 하위 문자열이 있는지 검색하는 스크립트를 작성하려고 합니다 .
시스템의 디렉터리(및 모든 하위 디렉터리)를 반복해야 할 수 있으므로 재귀 함수 만으로는 grep
충분하지 않으며 이로 인해 메모리 부족 및 중단이 발생할 수 있습니다. 따라서 스크립트에 전달된 매개 변수를 나타내는 다음 변수를 사용하여 지정된 디렉터리 트리의 모든 디렉터리 및 하위 디렉터리 목록을 가져오기로 결정했습니다 ./
grep
find
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/{*,.*}
,
그러면 보조기 확장이 일어나기에는 너무 늦습니다.
grep
literal이라는 파일을 찾으세요 /home/user/{*,.*}
.
폴리스티렌
grep -sHn "${searchstr}" "${line}/{*,.*}"
따옴표는 중괄호 확장 및 경로 이름 확장이 발생하는 것을 방지하기 때문에 작동하지 않습니다.
조달청: 교정기는 그렇게 많이 필요하지 않습니다.
grep -sHn "$searchstr" "$line"/{*,.*}
그게 다야.
답변2
grep이 시스템 전체에서 반복되는 동안 중단되는 이유는 아마도 많은 양의 데이터를 처리할 수 없기 때문이 아니라 /proc, /sys 또는 /dev에 있는 하나 이상의 의사 파일이나 장치 파일에서 오류가 발생하기 때문일 것입니다. . --exclude
명령줄의 옵션을 사용하여 문제가 있는 디렉터리를 제외 할 수 있습니다 .
와일드카드 문자를 확장하지 않는 이유는 다음 줄에서 인용되기 때문입니다.
grepdir="${line}/{*,.*}"
이를 변경하면 확장에 도움이 될 수 있습니다.
grepdir="${line}/"{*,.*}
이를 달성하는 또 다른 방법(사용자를 대신하여 더 적은 스크립트 작성)은 파일 경로를 사용하여 파일을 선택 하고 처리할 find
파일 경로를 전달하는 것입니다 .xargs
find / ... -print 0 | xargs -0 ...
그러나 어느 쪽이든 원래 재귀 grep이 발견한 파일을 제외하지 않는 한 여전히 발견될 수 있습니다.