일부 기능을 포함 .bashrc
하고 있는 파일이 있습니다 . .zshrc
이전에는 각 셸에 대해 두 개의 별도 파일이었지만 지금은 파일이 거의 동일하고 단일 함수 파일을 관리하는 것이 더 쉽기 때문에 단일 파일을 사용합니다.
두 쉘 모두 서로 다른 기능이 있으므로 올바른 명령문이 사용되도록 조건문을 사용할 수 있다고 생각했습니다.
[[ $BASH_VERSION ]] && shell=bash
[[ $ZSH_VERSION ]] && shell=zsh
# Search man page for string
if [[ $shell == bash ]]; then
mans() {
local q="\'"
local q_pattern="'${1//$q/$q\\$q$q}'"
local MANPAGER="less -+MFX -p $q_pattern"
man "$2"
}
elif [[ $shell == zsh ]]; then
mans() MANPAGER="less -+MFX -p ${(q+)1}" man $2
fi
이것은 zsh에서는 잘 작동하는 것 같지만 bash로 전환하면 bash에서 사용해서는 안 되지만 zsh 라인에서 오류가 발생합니다. 해당 줄을 구문 분석하는 것을 막을 수 있는 방법이 있나요?
답변1
ifbash
예를 들어 다음과 같은 일부 , ifzsh
, 별칭을 정의할 수 있습니다 endif
.
alias if{ba,z}sh=':||:<<"endif"' endif=
if [[ -n $BASH_VERSION ]]; then
alias ifbash=
shopt -s expand_aliases
elif [[ -n $ZSH_VERSION ]]; then
alias ifzsh=
fi
ifbash
f() { echo bash; }
endif
ifzsh
f() echo ${(q+):-zsh}
endif
:||:<<"MARKER"
...은 MARKER
코드 섹션을 주석 처리하는 관용적인 방법입니다. 이는 stdin에서 here-doc를 사용하여 내장된 noop를 :<<"MARKER"
실행하는 것과 비슷하지만 추가로 두 번째 문서는 실행되지 않고 here-document도 생성되지 않고 구문 분석만 됩니다.:
:||
:
들여쓰기를 해서 endif
도 안 되고, 뒤에 아무것도 추가해서도 안 됩니다. 전체 줄을 구성해야 합니다. ifbash
/ ifzsh
s는 중첩될 수 없습니다(어쨌든 여기서는 의미가 없습니다).
그런데, 인용 구문 분석은 환경 변수에서 별도로 수행되는 것으로 man
보이며 MANPAGER
(쉘을 호출하는 대신 ) 인용 형식을 $SHELL
지원하지 않는 것 같으 므로 일부 문자열의 매개변수 확장 플래그를 사용하면 해당 형식을 사용할 수 있습니다. 인용문이 잘못되었습니다. 대신 bash 버전에서처럼 작은 따옴표를 사용하고 따옴표 외부에서 작은 따옴표를 이스케이프 처리하는 방법을 사용하세요 .$'...'
q+
qq
\'
¹ rcquotes
이 옵션을 활성화 하지 않으면 ''
à la가 대신 사용됩니다. 함수 내에서 합리적인 로컬 옵션 세트를 갖는 것을 함수 시작 부분에 rc
추가하면 emulate -L zsh
함수가 실행되지 않고 정의될 때 옵션을 비활성화해야 하기 때문에 도움이 되지 않습니다.
답변2
배쉬는 여전히 필요하다분석하다모든 줄을 실행하지는 않더라도 전체 파일입니다. 넌 보통 숨길 수 없어통사론다음 오류는 조건부 오류이며 런타임 오류일 뿐입니다.
당신 대신에 나는 별도의 .zshrc
및 .bashrc
. 그런 다음 일반적으로 사용되는 기능을제삼파일(파일이 두 가지 모두와 호환되는 구문만 사용하는지 확인) 및 에서 가져 .zshrc
옵니다 .bashrc
.
제 생각에는 이것이 세계 최고입니다.
- zsh 전용 기능은
.zshrc
bash가 절대 읽을 수 없는 위치로 이동합니다. 마찬가지로 bash 전용 콘텐츠는.bashrc
. - 범용 함수에는 하나의 정의가 있으므로 두 개의 복사본을 유지할 필요가 없습니다(명시적으로 크로스 쉘인 파일에 있으므로 두 복사본과의 호환성을 유지하는 것을 잊어버릴 가능성이 적습니다).
- 각 셸에는 정규화된 이름이 포함된 자체 시작 파일이 있어 이를 구성할 위치가 더 명확하며, 각 셸에는 공용 파일도 사용한다고 명시적으로 명시되어 있습니다.
- 쉘 문자열 내에서 쉘 구문을 유지할 필요가 없습니다(예제보다 인용이 더 복잡하거나 구문 강조 표시가 손실될 때 문제가 됩니다).
답변3
다른 이유가 없다면 모든 쉘은 조건이 끝나는 부분을 찾기 위해 조건의 코드를 구문 분석해야 합니다.
쉘 특정 코드를 다른 파일이나 문자열에 넣는 대신 eval
here-doc를 사용하여 source
숨기고 here-doc를 직접 숨길 수 있습니다. 를 사용하는 것과 거의 동일 eval
하지만 here-doc의 장점은 내부 코드에 성가신 이스케이프 문제 없이 작은따옴표와 큰따옴표를 포함할 수 있다는 것입니다.
예를 들어, 이 스크립트는 hello, 'bar', I'm zsh
zsh로 실행하면 Bash에서 오류가 발생한다고 말합니다.
if [[ -n $ZSH_VERSION ]]; then
source /dev/stdin <<'EOF'
foo() {
echo "hello, '$1', I'm zsh"
}
EOF
fi
foo bar
그러나 이것이 source /dev/stdin
모든 쉘과 시스템에서 작동하는지 확실하지 않습니다. (예, source
이것은 내장 명령의 비표준 이름이지만 .
Bash 및 zsh에서 작동해야 하며 명령은 어쨌든 실행 조건 내의 셸에만 존재하면 됩니다.)
답변4
방법@ilkkachu가 제안한 것일하다:
# Search man page for string
if [[ $shell == bash ]]; then
mans() {
local q="\'"
local q_pattern="'${1//$q/$q\\$q$q}'"
local MANPAGER="less -+MFX -p $q_pattern"
man "$2"
}
elif [[ $shell == zsh ]]; then
mansfunc='mans() MANPAGER="less -+MFX -p ${(q+)1}" man $2'
eval "$mansfunc"
fi