diff를 사용한 명령에서 변수가 확장되지 않음

diff를 사용한 명령에서 변수가 확장되지 않음

내 쉘은 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.esfish

를 사용하여 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

관련 정보