다음과 같은 대답이것패스를 제어하는 방법에 대한 훌륭한 설명모두명령에 대한 변수.
매개변수별로 이 작업을 수행하는 방법을 알아보고 싶습니다. 관찰(이것은 에서 테스트되었습니다 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
첫 번째 인수가run2
run2
run
- 다른 Bourne 스타일 셸(예: bash)에서는
run $1
"split+glob" 연산자를 적용합니다$1
. 즉, 첫 번째 인수를run2
공백으로 구분된 청크로 분할하고1, 각 부분을 와일드카드 패턴2으로 해석하고, 이를 각 와일드카드 패턴 또는 여러 개로 바꿉니다. 일치 항목은 일치하는 목록으로 더 많은 파일을 표시합니다.
따라서 zsh에서는 인수와 함께 호출되지만 run2 'a b' c
(인수는 그대로 전달됨) bash에서는 두 개의 인수(공백으로 구분된 부분으로 분할)와 함께 호출됩니다.run
a b
run
a
b
$@
공백이 포함된 문자열인 첫 번째 인수를 전달하고 해당 스플라이스 스타일을 다른 명령에 전달하는 방법을 원합니다 . 예를 들어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 ksh
ksh의 특정 기능을 시뮬레이션하는 데 사용됩니다 . 이는 모든 bash 기능을 에뮬레이트하지는 않지만 배열을 사용할 수 있도록 해줍니다.
1더 일반적으로는 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
호출되거나 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
두 번째 줄은 다른 쉘의 두 번째 줄과 다릅니다.
이건 좋은 생각이야이 질문에 대한 답변을 읽어보세요