
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}"/*
중괄호 확장은 마지막 토큰을 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
파일 경로를 사용하고 파이핑하는 파일을 선택하는 것입니다.xargs
find / ... -print 0 | xargs -0 ...
그러나 어느 쪽이든 제외하지 않는 한 원래 재귀 grep이 넘어간 파일은 여전히 넘어갈 것입니다.