"find -regextype egrep"을 별칭으로 설정

"find -regextype egrep"을 별칭으로 설정

이제 막 정규식을 배우기 시작했는데 다른 정규식 대신 어디서나 정규식을 사용하는 연습을 하고 싶습니다.

확장자가 있는 파일을 찾으려고 할 때 이런 상황이 발생했습니다.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"

또한 결과에 추가하려면 bashglob 파일에 대한 고유한 방법도 있다는 점에 유의하세요. 작동하려면 몇 가지 확장 셸 옵션을 활성화하기만 하면 됩니다. 이 옵션을 활성화 -s하고 -u비활성화하십시오.

nullglob확장되지 않은 전역 결과를 유효한 일치 항목으로 무시할 수 있습니다 . 따라서 *.shand로 끝나는 파일을 일치시키려는 경우 *.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에서는 옵션이 아닌 술어를 통해 findERE를 활성화합니다 . -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.pyBRE를 사용했기 때문이 아니라 술어가 아닌 파일 이름으로 처리 되는 regex.-regexregex
  • 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를 다루고 있다는 사실이 불편할 것입니다.findfindfind --versionfind

관련 정보