Bash 변수를 "확장"하는 방법(포함된 코드는 bash에서는 작동하지만 zsh에서는 작동하지 않음)

Bash 변수를 "확장"하는 방법(포함된 코드는 bash에서는 작동하지만 zsh에서는 작동하지 않음)

다음과 같은 답변이것패스 제어 방법을 잘 설명해줍니다.모두명령을 통해 변수.

인수별로 이 작업을 수행하는 방법을 알아보고 싶었습니다. 관찰하십시오(이것은 에서 테스트되었습니다 zsh).

$ program() { echo 1: $1 2: $2 3: $3; }

$ run() { program "$@"; }

$ run2() { echo `run $1`; }

$ run2 'a b' c
1: a b 2: 3:

공백이 포함된 문자열인 첫 번째 인수를 전달하고 해당 $@스타일을 다른 명령에 연결하는 방법을 원합니다. 예를 들어 run2 "a b" c생산해야 한다1: a 2: b 3:

이 시점에서 나는 당면한 문제를 해결했습니다. 왜냐하면 테스트 코드가 zsh에서 테스트할 때 중단되더라도 일단 실제 bash 스크립트로 구현되면 작동하기 때문입니다.

이는 "안전"하지 않은 문자열 및 인수 처리의 일부 복잡성에 의존할 수 있음을 나타냅니다. 따라서 이는 이 동작을 안정적으로 달성하기 위한 보다 강력한 방법에 대한 의견을 요청하는 것입니다.

답변1

run2여기서 중요한 bash와 zsh의 차이점은 호출 방식 run, 특히 인용되지 않은 상태로 두는 효과에 있습니다 $1.

  • zsh에서는 run $1"비어 있으면 제거" 연산자를 에 적용합니다 . 즉 , 에 전달된 첫 번째 인수로 $1호출합니다 . 단, 의 첫 번째 인수가 비어 있는 경우(또는 인수 없이 호출된 경우) 는 없이 호출됩니다. 논쟁.runrun2run2run2run
  • Bash와 같은 다른 Bourne 스타일 셸에서는 run $1"split+glob" 연산자를 에 적용합니다 $1. 즉, 첫 번째 인수를 run2공백으로 구분된 청크로 분할하고, 각 조각을 와일드카드 패턴²으로 해석하고, 하나 또는 일치하는 각 와일드카드 패턴을 대체합니다. 일치 목록으로 더 많은 파일을 생성합니다.

따라서 zsh(인수는 변경되지 않은 상태로 전달됨)에서 인수를 사용하여 run2 'a b' c호출 하지만 두 인수 와 bash(공백으로 구분된 조각으로 분할)를 사용하여 호출합니다.runa brunab

공백이 포함된 문자열인 첫 번째 인수를 전달하고 해당 $@스타일을 다른 명령에 연결하는 방법을 원합니다. 예를 들어 run2 "a b" c생산해야 한다1: a 2: b 3:

귀하의 설명과 귀하의 예는 서로 다른 것을 말합니다. 첫 번째 인수를 다른 명령에 전달하려면 를 사용하여 run "$1"인수가 분할되지 않았는지 확인하세요. 인수를 변경하지 않고 전달하는 것이 "$@".

실제로 원하는 것은 첫 번째 인수를 run2공백으로 구분된 덩어리로 나누는 것 같습니다. Bash에서는 와일드카드 확장을 끈 다음 ( IFS기본값에서 변경되지 않는다고 가정하고) 인용되지 않은 확장을 사용하여 이를 수행할 수 있습니다.

run2 () ( set -f; run $1; )

( echo "$(somecommand)"기본적으로 서브셸에서 실행하는 것과 동일하며 명령 출력에 분할+glob을 적용하는 것이 somecommand아니라 이것이 의미하는 것으로 보이므로 중복된 echo-command-substitution을 제거했습니다.)echo $(somecommand)

zsh에서는 =매개변수 대체 문자를 사용하여 값에 대해 월드 분할(글로빙 없음)을 수행할 수 있습니다.

run2 () { run $=1; }

zsh의 구문은 일반 sh의 구문과 호환되지 않습니다. zsh에서 sh 스크립트를 소스로 사용하려면 emulate다음 건물을 사용할 수 있습니다.

emulate sh -c '. myscript.sh'

emulate kshksh의 일부 기능을 에뮬레이트하는 데 사용됩니다 . 이것은 모든 bash 기능을 에뮬레이션하지는 않지만 배열을 사용할 수 있도록 해줍니다.

¹ 보다 일반적으로는 의 값을 기준으로 합니다 IFS.
² 로 이 기능을 끄지 않은 경우 set -f.

답변2

인용과 놀라움의 세계에 오신 것을 환영합니다.

주요 문제는 zsh기본적으로 IFS 문자로 분할되지 않는다는 것입니다.
즉, 다른 모든 껍질과 다릅니다.

인용이 쉘 작동 방식을 어떻게 변경하는지 테스트하려면 인용된 버전과 인용되지 않은 코드 버전을 모두 테스트하는 코드가 필요합니다.

귀하의 코드(몇 가지 변수 추가):

program() { printf '%02d-1: %6s   2: %6s    3: %6s' "$i" "$1" "$2" "$3"; }
runa()  { program  "$@" ; }
run1()  { echo "`runa  $1 $2 $3 `"; }
run1    'a b' c

세부 사항을 확장해 보겠습니다.

sh거주지 를 가리키는 로컬 링크를 생성한다고 가정해 보겠습니다 zsh.

ln -s "/usr/bin/zsh" ./sh

그리고, 다음 스크립트를 파일에 복사한다고 가정해 보겠습니다 so.

인용된 변수와 인용되지 않은 변수를 사용하여 각 함수를 반복하는 스크립트:

program() { printf '%02d-1: %6s   2: %6s    3: %6s' "$i" "$1" "$2" "$3"; }
runa() { program "$@"; }
runb() { program  $@ ; }

run1() { echo "`runa  "$1" "$2" "$3"`"; }
run2() { echo "`runb  "$1" "$2" "$3"`"; }
run3() { echo "`runa  $1 $2 $3`"; }
run4() { echo "`runb  $1 $2 $3`"; }

for i in `seq 4`; do
    run"$i" 'a b' c
done

그런 다음 실행 시 다음이 인쇄됩니다.

# Any shell (except zsh) results.
01-1:    a b   2:      c    3:
02-1:      a   2:      b    3:      c
03-1:      a   2:      b    3:      c
04-1:      a   2:      b    3:      c

모두 인용된 첫 번째 실행(run1)만 계속 'a b'조인됩니다.

그러나 zsh는 모든 내용이 항상 인용된 것처럼 작동합니다.

# ZSH results.
01-1:    a b   2:      c    3:
02-1:    a b   2:      c    3:
03-1:    a b   2:      c    3:
04-1:    a b   2:      c    3:

zsh를 에뮬레이션 중입니다.

또는 zsh로 호출되면 이전 쉘을 에뮬레이션할 것으로 예상됩니다 . 그러나 실제로 이것은 항상 사실이 아닙니다.shksh

$ ./sh ./so   # emulated sh
01-1:    a b   2:      c    3:
02-1:    a b   2:      c    3:
03-1:      a   2:      b    3:      c
04-1:      a   2:      b    3:      c

두 번째 줄은 다른 쉘의 두 번째 줄과 다릅니다.

다음을 수행하는 것이 좋습니다.이 질문에 대한 답을 읽어보세요

관련 정보