이제 막 정규식을 배우기 시작했는데 다른 정규식 대신 어디서나 정규식을 사용하는 연습을 하고 싶습니다.
확장자가 있는 파일을 찾으려고 할 때 이런 상황이 발생했습니다.sh or md
$ find . regex ".*\.(sh|md)$"
.
./bogus.py
./cofollow.py
./data8.txt
./example.sh
./longest_word_2.sh
./posit_param.sh
./cobroadcast2.py
불행히도 그것은 출력됩니다 /bogus.py
.
BRE 규칙을 발견하고 탈출을 시도했습니다.()
$ find . -regex ".*\.\(sh|md\)$"
#get nothing return
일련의 검색 끝에 -regextype 솔루션을 얻었습니다.정규식 - 파일 찾기
$ find . -regextype posix-extended -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
$ find . -regextype egrep -iregex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md
또한, 좋은 모듈식 솔루션
$ find -type f | egrep ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
./table_regex_bat.md
그러나 BSD에는 술어를 사용하여 이러한 작업을 수행하는 지름길이 있습니다 -E
.
$ /usr/bin/find -E . -regex ".*\.(sh|md)$"
./example.sh
./longest_word_2.sh
./posit_param.sh
나는 내 코드와 기술을 이식 가능하게 만들기 위해 GNU 도구만 사용하기로 결정했습니다.
그래서 "find -regextype egrep"이라는 별칭을 지정하기 시작했고
불행히도 find는 경로로 $1을 얻었습니다.
어떻게 하면 문제를 편리하게 해결할 수 있나요?
답변1
alias
매개변수를 전달하는 데를 사용하지 마세요 . 이식성이 없으며 대화형 쉘에서만 유용합니다. 대신 함수를 사용하고 매개변수를 원하는 경로로 전달하세요.
regexFind() {
(( "$#" )) || { printf 'Insufficient arguments provided \n' >&2; return 1; }
find "$1" -regextype egrep -iregex ".*\.(sh|md)$"
}
함수를 다음과 같이 호출합니다.
regexFind "/home/foo/bar"
또한 결과에 추가하려면 bash
glob 파일에 대한 고유한 방법도 있다는 점에 유의하세요. 작동하려면 몇 가지 확장 셸 옵션을 활성화하기만 하면 됩니다. 이 옵션을 활성화 -s
하고 -u
비활성화하십시오.
nullglob
확장되지 않은 전역 결과를 유효한 일치 항목으로 무시할 수 있습니다 . 따라서 *.sh
and로 끝나는 파일을 일치시키려는 경우 *.md
해당 특정 디렉터리로 이동하여 다음을 수행하면 됩니다.
shopt -s nullglob
fileList=(*.sh)
fileList+=(*.md)
shopt -u nullglob
그리고 아래와 같이 결과를 인쇄해 보세요. 파일 이름이 토큰화되는 것을 방지하려면 확장자를 인용하는 것을 잊지 마세요.
printf '%s\n' "${fileList[@]}"
답변2
GNU 의 기본 정규식은 BRE가 아니라 일부 고대 버전의 GNU (예를 들어 BRE와 ERE 간의 일부 하이브리드, 지원되지만 필요 하고 지원되지만 ) find
의 정규식입니다 .emacs
+
\(...\)
|
\|
BSD의 경우 find
기본값은 BRE입니다. 이 -E
옵션을 사용하여 ERE를 활성화할 수 있으므로 다음을 수행하십시오.
alias efind='find -E'
또는:
efind() { find -E "$@"; }
GNU에서는 옵션이 아닌 술어를 통해 find
ERE를 활성화합니다 . -regextype posix-extended
조건자는 파일 이름 뒤(있는 경우), 옵션 뒤, 또는 -regex
사용 앞에 나타나야 합니다.-iregex
GNU find
구문은 다음과 같습니다:
find [options] [files] [predicates]
^
따라서 해당 위치(표시된 위치)에 삽입해야 합니다 ^
.
따라서 래퍼 함수나 스크립트를 정의할 때 이 점을 고려해야 합니다. 모든 옵션과 파일 이름을 건너뛰고 -regextype posix-extended
그 뒤에 삽입하세요.
efind() (
found_predicate=false
for arg do
"$found_predicate" || case $arg in
(-[LPDd]|-[OD]*) ;; # skip options
(-*|['()!'])
set -- "$@" -regextype posix-extended
found_predicate=true;;
esac
set -- "$@" "$arg"
shift
done
exec find "$@"
)
기타 참고사항:
- 첫 번째 인쇄는
bogus.py
BRE를 사용했기 때문이 아니라 술어가 아닌 파일 이름으로 처리 되는regex
.-regex
regex
find . | egrep ...
파일 경로가 여러 줄로 구성될 수 있으므로 유효하지 않습니다. GNU 도구 또는 호환 도구를 사용하면 NUL로 구분된 레코드를 처리할 수 있습니다find . -print0 | grep -zE ...
(tr '\0' '\n'
또는 표시에 사용되는 경우 파이프로 연결).
답변3
find . -type f \( -name '*.sh' -o -name '*.md' \)
find
이는 정규식 일치를 지원할 필요가 없으므로 모든 구현에 적용됩니다 .
더 유연하게 만들려면:
suffixfind () (
dir=$1
shift
for suf do
set -- "$@" -o -name "*.$suf"
shift
done
shift
find "$dir" -type f \( "$@" \)
)
유사한 쉘에서 작동 하는 이 도우미 쉘 함수는 sh
첫 번째 명령줄 인수를 선택하여 변수에 넣습니다 dir
. 그런 다음 -name "*.<suf1>" -o -name "*.<suf2>" (etc.)
함수의 명령줄에서 모든 파일 이름 접미사의 목록을 구성하고 find
해당 목록을 호출하여 $dir
.
이렇게 사용하시면 될 것 같아요
suffixfind /usr sh md txt
.sh
이름이 로 끝나 거나 경로 안이나 아래에 .md
있는 모든 일반 파일을 찾습니다 ..txt
/usr
bash
배열과 지역 변수를 사용하여 bash
위의 내용을 보다 자세히 변형한 방법은 다음과 같습니다 .
suffixfind () {
local dir=$1
shift
local names
names=( -name "*.$1" )
shift
for suf do
names+=( -o -name "*.$suf" )
done
find "$dir" -type f \( "${names[@]}" \)
}
GNU 도구 및 이식성에 대한 언급과 관련하여 Linux가 아닌 시스템에서도 GNU 도구를 사용할 수 있지만 g
도구 이름에 접두사가 붙는다는 점에 유의하세요. 따라서 GNU는 find
이를 시스템의 기본 구현과 gfind
구별 할 수 있습니다.find
따라서 "GNU 이식 가능한" 방법은 gfind
실제로 GNU인지 테스트하기 전에 사용 가능한지 여부를 테스트해야 합니다. 이 작업을 수행하기 전까지는(아마도 상태와 출력을 반환하는 테스트를 통해) GNU를 다루고 있다는 사실이 불편할 것입니다.find
find
find --version
find