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

bash와 zsh의 중요한 차이점은 run2호출 방식 run, 특히 따옴표를 사용하지 않을 때의 효과입니다 $1.

  • zsh에서는 run $1"비어 있으면 제거" 연산자가 적용됩니다 $1. 즉, run첫 번째 인수가 에 전달되어 호출될 때 인수 없이 호출되는 경우)비어 있는 경우(또는run2첫 번째 인수가run2run2run
  • 다른 Bourne 스타일 셸(예: bash)에서는 run $1"split+glob" 연산자를 적용합니다 $1. 즉, 첫 번째 인수를 run2공백으로 구분된 청크로 분할하고1, 각 부분을 와일드카드 패턴2으로 해석하고, 이를 각 와일드카드 패턴 또는 여러 개로 바꿉니다. 일치 항목은 일치하는 목록으로 더 많은 파일을 표시합니다.

따라서 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 기능을 에뮬레이트하지는 않지만 배열을 사용할 수 있도록 해줍니다.

1더 일반적으로는 IFS.
² 이 기능이 꺼져 있지 않은 경우 set -f.

답변2

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

주요 문제는 zshIFS 문자로 분할이 기본적으로 수행되지 않는다는 것입니다.
거기: 그것은 다른 모든 껍질과 다릅니다.

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

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

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호출되거나 sh이전 쉘을 에뮬레이트해야 합니다 ksh.
그러나 실제로 이것은 항상 사실이 아닙니다.

$ ./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

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

이건 좋은 생각이야이 질문에 대한 답변을 읽어보세요

관련 정보