편집 2

편집 2

다음 명령을 가정

search /home/user proc .h .c .txt ...

find주어진 이름으로 시작하고 주어진 확장자 중 하나로 끝나는 모든 파일을 가져오는 명령을 사용하여 스크립트를 작성 중입니다 .

루프를 사용하여 성공적으로 구축했습니다.

directory=$1
fileName=$2
fileExtensions=""

for arg in "$@"
do
    #skipping first and second argument
     if [ $arg = $1 -o $arg = $2 ]; then 
        continue;
    fi
    fileExtensions+="${arg//.}\|"
done
#removing the last '|', otherwise regex parser error occurs
fileExtensions=${fileExtensions::-1}

find $directory -name "$fileName*" -regex ".*\.\($fileExtensions)"

정규식을 사용하여 이를 달성하는 더 우아한 방법이 있습니까?

당신의 도움을 주셔서 감사합니다!

답변1

스크립트는 다음과 같이 단순화될 수 있습니다.

directory=$1
fileName=$2
shift 2

a="$*"    b="${*#.}"
(( ${#a} - ${#b} - $# )) && echo "some extension(s) is(are) missing a leading dot." >&2

fileExtensions="$(IFS=\|; echo "${*#.}")"

find "$directory" -name "$fileName*" -regextype posix-egrep -regex ".*\.($fileExtensions)$"

기본적으로 find는 emacs 유형의 정규식을 허용하며 해당 유형을 사용하려면 몇 가지 백슬래시가 필요합니다 \|(예: 위에서 언급한 것처럼). 이는 다른 유형의 정규식을 사용하면 피할 수 있습니다.

선행 점(있는 경우)을 제거 하고 나머지 모든 "위치 인수"를 서브쉘 실행에 ${*#.}사용되도록 설정된 IFS의 첫 번째 문자 값과 연결합니다 .|

변수 할당과 "매개변수 확장"만으로 충분합니다.


편집하다
(( ${#a} - ${#b} - $# ))매개변수 목록에 제공된 모든 확장자가 점으로 시작하는지 확인하는 데 사용됩니다 .

${#a}연결의 모든 매개변수의 문자 수( )( a=$*)는 연결의 모든 매개변수의 문자 수 ( )(앞의 점 하나 제거됨)( ) 에 매개변수 수( )를 더한
값과 같아야 합니다 .
${#b}b=${*#.}

$#

${#a} == ${#b} + $#

모든 인수에 앞에 점이 있는 경우.

산술 테스트:

((  ${#a} - (${#b} + $#)  ))

또는:

((  ${#a} - ${#b} - $#  )) && echo "missing leading dot(s)."

편집 2

명령줄 인수에 제공된 확장 목록은 여기에서 처리됩니다.

fileExtensions="$(IFS=\|; echo "${*#.}")"

내부 및 외부 작동 방식은 다음과 같습니다.

$*   # This generates a string of all positional arguments using IFS.

에서 LESS=+'/Special Parameters' man bash:

즉, "$*"는 "$1c$2c..."와 동일합니다. 여기서 c는 IFS 변수 값의 첫 번째 문자입니다.

그런 다음 "매개변수 확장"을 사용하여 각 위치 매개변수의 앞 부분을 잘라냅니다.

${parameter#word}     # used as ${*# } above.

에서 LESS=+/'parameter#word' man bash:

인수가 @ 또는 *인 경우 패턴 제거 작업이 각 위치 인수에 차례로 적용되고 확장이 결과 목록이 됩니다.

word이전 확장의 점으로 설정되어 .모든 위치 매개변수 앞의 점이 제거되었습니다.

이때 IFS는 |문자로 시작하므로 해당 문자는 문자열을 구성하는 데 사용되며 |앞에 점이 제거된 매개변수 목록의 구분 기호 역할을 합니다.

이 문자열은 인쇄하기 위해 echo 명령에 제공됩니다.
그러나 echo 명령을 실행하기 전에 변수 $IFS|.

이는 명령 실행으로 래핑됩니다 $(…)(종료 시 IFS에 대한 변경 사항을 잊어버리는 하위 쉘 생성).

그런 다음 문자열을 변수에 할당합니다.

fileExtensions="$(IFS=\|; echo "${*#.}")"

즉, .c .h .txt로 변환합니다 c|h|txt.

답변2

정규 표현식이 작동해야 하는 것 같고, 제가 생각할 수 있는 유일한 다른 옵션은 비슷한 것인데 -name "proc*" \( -name "*.c" -o -name "*.h" ... \) 그렇게 간단하지 않을 수도 있습니다.

당신이 할 수 있는 몇 가지 작은 일들:

shift1) 루프 내부의 조건을 대체하기 위해 및 를 사용할 수 있습니다 .$1$2

2) 결합하여 -name결국 -regex에는 얻을 수 있습니다.-regex ".*/proc.*\.(c|h|txt)"

3) 코드를 더 짧게 만들고 싶다면 IFS위치 매개변수를 사용하여 연결할 수 있습니다 $*.

$ set .c .h
$ IFS='|'
$ echo "(${*/./})"
(c|h)

(가독성이나 우아함을 의미하는 것은 아닙니다.)

관련 정보