zsh vs bash:括号如何改变变量赋值行为?

zsh vs bash:括号如何改变变量赋值行为?,bash,shell,zsh,Bash,Shell,Zsh,对于变量赋值和括号在不同的现有shell中是如何处理的,我有一些问题和误解 目前令我困惑的是: 始终使用以下命令 ./script.sh a b c d 当运行以下代码时 #!/bin/zsh bar=$@ for foo in $bar do echo $foo done 输出是 a b c d 和 #!/bin/zsh bar=($@) for foo in $bar do echo $foo done 这是(我最初想要的) 但是使用bash或sh #!/bi

对于变量赋值和括号在不同的现有shell中是如何处理的,我有一些问题和误解

目前令我困惑的是:

始终使用以下命令

./script.sh a b c d
当运行以下代码时

#!/bin/zsh

bar=$@

for foo in $bar
do
    echo $foo
done
输出是

a b c d

#!/bin/zsh

bar=($@)

for foo in $bar
do
    echo $foo
done
这是(我最初想要的)

但是使用bash或sh

#!/bin/bash

bar=$@

for foo in $bar
do
    echo $foo
done
给予

只是

a
发生了什么事?

执行此操作时:

bar=($@)
实际上,您正在创建bash shell数组。要迭代bash数组,请使用:

bar=( "$@" ) # safer way to create array
for foo in "${bar[@]}"
do
    echo "$foo"
done
联合作战 对于涉及的两个shell,给出的示例将假定显式设置argv列表:

# this sets $1 to "first entry", $2 to "second entry", etc
$ set -- "first entry" "second entry" "third entry"
在这两种shell中,
declare-p
可用于以明确的形式发出变量名的值,尽管它们表示形式可能有所不同

在狂欢节上 bash中的扩展规则通常与ksh兼容,如果适用,还与posixsh语义兼容。要与这些shell兼容,无引号扩展需要执行字符串拆分和全局扩展(例如,用当前目录中的文件列表替换
*

在变量赋值中使用括号使其成为数组。比较这三项作业:

# this sets arr_str="first entry second entry third entry"
$ arr_str=$@
$ declare -p arr_str
declare -- arr="first entry second entry third entry"

# this sets arr=( first entry second entry third entry )
$ arr=( $@ )
declare -a arr='([0]="first" [1]="entry" [2]="second" [3]="entry" [4]="third" [5]="entry")'

# this sets arr=( "first entry" "second entry" "third entry" )
$ arr=( "$@" )
$ declare -p arr
declare -a arr='([0]="first entry" [1]="second entry" [2]="third entry")'
同样,在展开时,引号和符号也很重要:

# quoted expansion, first item only
$ printf '%s\n' "$arr"
first entry

# unquoted expansion, first item only: that item is string-split into two separate args
$ printf '%s\n' $arr
first
entry

# unquoted expansion, all items: each word expanded into its own argument
$ printf '%s\n' ${arr[@]}
first
entry
second
entry
third
entry

# quoted expansion, all items: original arguments all preserved
$ printf '%s\n' "${arr[@]}"
first entry
second entry
third entry
在zsh中 zsh做了大量的魔术来尝试做用户想要做的事情,而不是与历史shell(ksh、POSIX sh等)兼容的事情。然而,即使在那里,做错事也可能会产生你不想要的结果:

# Assigning an array to a string still flattens it in zsh
$ arr_str=$@
$ declare -p arr_str
typeset arr_str='first entry second entry third entry'

# ...but quotes aren't needed to keep arguments together on array assignments.
$ arr=( $@ )
$ declare -p arr
typeset -a arr
arr=('first entry' 'second entry' 'third entry')

# in zsh, expanding an array always expands to all entries
$ printf '%s\n' $arr
first entry
second entry
third entry

# ...and unquoted string expansion doesn't do string-splitting by default:
$ printf '%s\n' $arr_str
first entry second entry third entry

…创建阵列时出错;它必须是
bar=(“$@”)
,以防止字符串拆分和全局搜索。谢谢@CharlesDuffy,我已经相应地编辑了答案。
# this sets arr_str="first entry second entry third entry"
$ arr_str=$@
$ declare -p arr_str
declare -- arr="first entry second entry third entry"

# this sets arr=( first entry second entry third entry )
$ arr=( $@ )
declare -a arr='([0]="first" [1]="entry" [2]="second" [3]="entry" [4]="third" [5]="entry")'

# this sets arr=( "first entry" "second entry" "third entry" )
$ arr=( "$@" )
$ declare -p arr
declare -a arr='([0]="first entry" [1]="second entry" [2]="third entry")'
# quoted expansion, first item only
$ printf '%s\n' "$arr"
first entry

# unquoted expansion, first item only: that item is string-split into two separate args
$ printf '%s\n' $arr
first
entry

# unquoted expansion, all items: each word expanded into its own argument
$ printf '%s\n' ${arr[@]}
first
entry
second
entry
third
entry

# quoted expansion, all items: original arguments all preserved
$ printf '%s\n' "${arr[@]}"
first entry
second entry
third entry
# Assigning an array to a string still flattens it in zsh
$ arr_str=$@
$ declare -p arr_str
typeset arr_str='first entry second entry third entry'

# ...but quotes aren't needed to keep arguments together on array assignments.
$ arr=( $@ )
$ declare -p arr
typeset -a arr
arr=('first entry' 'second entry' 'third entry')

# in zsh, expanding an array always expands to all entries
$ printf '%s\n' $arr
first entry
second entry
third entry

# ...and unquoted string expansion doesn't do string-splitting by default:
$ printf '%s\n' $arr_str
first entry second entry third entry