for 루프 범위의 와일드카드 확장 문제

for 루프 범위의 와일드카드 확장 문제

내가 만든 bash 스크립트에 문제가 있습니다. for 루프 내에서 모든 매개변수를 반복하여 나중에 "eval" 명령에 입력될 문자열 변수를 구성합니다.

    for arg in "$*"
    do
        if [ $arg != $lastArg ]; then
            findTarget+="-name $arg -o "
        else
            findTarget=$(echo $findTarget | sed 's/-o$//')
            break
        fi
    done

문제는 "$*"에서 발생합니다. 예를 들어, 매개변수에 "*.c"를 입력하고 현재 폴더에 해당 패턴과 일치하는 파일이 포함되어 있으면 매개변수가 *.c해당 파일로 확장됩니다. 저는 이를 원하지 않습니다. findTarget와 연결 하려고 -name *.c -o합니다. eval을 사용하고 따옴표 없이는 효과가 없는 것 같습니다. 이 작업을 수행하는 방법을 아시나요(가능하다면 간단하게)? 참고: 총 매개변수 수는 다를 수 있습니다.

다음은 스크립트를 실행하는 방법의 예입니다.

$ trouver.bash *.c *.f90 someString

내 for 루프가 끝나면 변수는 findTarget다음과 같아야 합니다.-name *.c -o -name *.f90

*.c*.f90현재 폴더의 파일과 일치 하거나 일치하는 경우에는 아무런 효과가 없습니다.

답변1

위치 매개변수를 반복하는 구문은 for arg do별개입니다. "$*"는 첫 번째 문자와 위치 인수를 연결한 것이므로 $IFS하나의 요소만 반복하게 됩니다.

또한 명령에 대한 매개변수 목록을 작성하려면 find문자열이 아닌 배열이 필요합니다. 그리고 변수를 인용하는 것을 잊지 마세요!

그래서:

findTarget=()
or=()
for arg
do
    [ "$arg" = "$lastArg" ] && break
    findTarget+=("${or[@]}" -name "$arg")
    or=(-o)
done

find . \( "${findTarget[@]}" \)

스크립트를 호출할 때 필요한 사항에 유의하세요.인용하다...mode *.c그렇지 않으면 스크립트에 전달되기 전에 셸에 의해 확장됩니다.

trouver.bash '*.c' '*.f90' someString

대화형 셸이 인 경우 zsh와일드카드를 비활성화하여 명령에 대한 별칭을 정의할 수 있습니다.

alias trouver.bash='noglob trouver.bash'

이 방법으로 다음을 수행할 수 있습니다.

trouver.bash *.c *.f90 someString

이 구체를 확장하는 껍질은 없습니다 *.c *.f90.

답변2

"$*"모든 매개변수를 하나의 긴 매개변수로 연결하려면 메서드를 사용하세요 . 이를 다음으로 변경하면 "$@"인수 목록이 제공됩니다. 하지만 실제로 for arg in "$@"올바른 관용구를 사용할 필요는 없습니다 for arg.

-o그런 다음 각 새 매개변수에 대해 하나를 추가하여 사용할 수 있습니다 ${findTarget[@]+"-o "}.
값이 할당되지 않으면 null이 되고, 값이 할당되면 findTarget일반 문자열이 됩니다. 첫 번째 루프 실행에서는 null로 축소되고 다음 루프에서는 null이 됩니다.-ofindTarget-o

(( $# < 1 )) && echo "please provide some argument(s)" && exit 1

unset  findTarget
for    arg
do     [[ "$arg" == "$lastArg" ]] && break
       findTarget+=("${findTarget[@]+"-o "}-name $arg")
done

find . \( "${findTarget[@]}" \)

다음과 같이 스크립트를 실행해야 합니다.

$ trouver.bash '*.c' '*.f90' someString

원하는 대로 각 인수는 쉘에 의해 확장되지 않습니다(작은따옴표를 사용하십시오. 큰따옴표는 작동할 수 있지만 확장 없이 인수를 유지하려는 의도를 명확하게 표현하지는 않습니다).

"작은따옴표" 없이 스크립트를 사용해야 하는 경우 "경로 이름 확장"(set -f)을 제거하여 확장을 방지할 수 있습니다 *.

$ ( set -f; trouver.bash *.c *.f90 someString )

이렇게 하면 ()noglob에 대한 변경 사항이 현재 실행 중인 쉘에 영향을 미치는 것을 방지할 수 있습니다.

이는 스크립트가 결과를 작성 stdout하고 하위 쉘 내에서 인쇄할 수도 있기 때문에 작동합니다 (…).

관련 정보