내 쉘은 zsh입니다. Bash에서 이 명령을 시도했는데 작동했습니다.
ignore_files=(
local
\*.local.\*
.bundle
Gemfile.lock
)
ignore_command=""
for f in "${ignore_files[@]}"; do
ignore_command="$ignore_command -x $f"
done
echo $ignore_command
# print: -x local -x *.local.* -x .bundle -x Gemfile.lock
sudo diff -ruNd $ignore_command <path a> <path-b>
# failed: diff: extra operand '<path-b>'
echo sudo diff -ruNd $ignore_command <path a> <path-b>
# sudo diff -ruNd -x local -x *.local.* -x .bundle -x Gemfile.lock <path a> <path-b>
eval diff -ruNd $ignore_command <path a> <path-b> # success
변수가 명령에서 확장되지 않는 것 같습니다. eval 없이 bash처럼 만드는 이유와 방법을 알고 싶습니다.
답변1
명령은 매개변수 목록이며 배열을 사용하여 이러한 매개변수를 저장하려고 합니다.
ignore_files=(
local
'*.local.*'
.bundle
Gemfile.lock
)
ignore_command=()
for f in "${ignore_files[@]}"; do
ignore_command+=(-x "$f")
done
print -r -- "${(q+)ignore_command[@]}"
sudo diff -ruNd "${ignore_command[@]}" <path a> <path-b>
Bourne과 같은 쉘의 동작으로 인해 혼란스러울 수 있습니다. 여기서 인용되지 않은 인수 확장은 분할+글로브 연산자이므로 문자열/스칼라 변수를 목록(또는 패턴과 일치하는 파일)으로 변환합니다.확장 후.
이 잘못된 동작은 , zsh
와 같은 대부분의 다른 최신 쉘 에 의해 수정 되었습니다 rc
.es
fish
를 사용하여 Bourne 쉘의 동작을 시뮬레이션할 수 있지만 set -o shwordsplit -o globsubst
이로 인해 회귀가 발생합니다. 특히 귀하의 경우 전역 문자가 포함되어 globsubst
문제가 발생합니다 .*.local.*
에서 zsh
변수를 분할하거나 확장 시 와일드카드를 수행하려면 명시적으로 요청해야 합니다.
$=var
, 문자$var
별로 구분됩니다$IFS
.${(s:,:)var}
특정 문자열을 기준으로 분할(여기,
)$~var
: 확장 시 와일드카드 지정(또는 컨텍스트에 따라 패턴 일치)을 수행합니다. (예: Contains$var
인 경우 목록 컨텍스트는 Bourne 쉘에서와 같이 현재 디렉터리의 파일 목록으로 확장됩니다 .)*
$~var
$var
$=~var
$var
: Bourne 쉘과 마찬가지로 분할과 와일드카드를 동시에 수행합니다 .
이 특별한 경우에는 다음을 수행할 수도 있습니다.
sudo diff -ruNd --exclude=$^ignore_files <path a> <path-b>
( ^
어레이가 in fish
또는 ... rc
처럼 확장되는 경우 실제로 및 활성화 와 같은 해당 확장 옵션을 --exclude=element1
--exclude=element2
활성화합니다 ).rcexpandparam
~
globsubst
=
shwordsplit