Shell 传递参数
$0..$9、$#、$@ 与 $* 的区别、shift、参数校验。
Key Points$@ 保留每个参数的原样(推荐加引号),$* 会拼成一个字符串;参数个数用 $#。
位置参数
Bash
#!/bin/bash
echo "script: $0"
echo "first : $1"
echo "second: $2"
echo "count : $#"Bash
cat > args.sh <<'EOF'
#!/bin/bash
echo "script: $0"
echo "first : $1"
echo "second: $2"
echo "count : $#"
EOF
bash args.sh alpha betaOutput
script: args.sh
first : alpha
second: beta
count : 2| Variable | Meaning |
|---|---|
$0 | Script name |
$1 … $9 | Positional parameters |
${10} | Tenth and beyond need braces |
$# | Number of arguments |
$@ | All args as separate words |
$* | All args joined into one string |
$$ | PID of the current shell |
$? | Exit code of the last command |
$@ 与 $*
Bash
#!/bin/bash
echo "with @:"
for a in "$@"; do echo " [$a]"; done
echo "with *:"
for a in "$*"; do echo " [$a]"; doneBash
cat > atstar.sh <<'EOF'
#!/bin/bash
echo "with @:"
for a in "$@"; do echo " [$a]"; done
echo "with *:"
for a in "$*"; do echo " [$a]"; done
EOF
bash atstar.sh "a b" cOutput
with @:
[a b]
[c]
with *:
[a b c]The difference shows inside quotes: "$@" expands to two words (a b, c), while "$*" collapses into one (a b c). Always forward arguments with "$@".
shift
Bash
#!/bin/bash
echo "before: $# args, first=$1"
shift
echo "after : $# args, first=$1"Bash
cat > shift.sh <<'EOF'
#!/bin/bash
echo "before: $# args, first=$1"
shift
echo "after : $# args, first=$1"
EOF
bash shift.sh one two threeOutput
before: 3 args, first=one
after : 2 args, first=two参数校验
Bash
#!/bin/bash
set -euo pipefail
if [ $# -lt 1 ]; then
echo "usage: $0 <name>" >&2
exit 2
fi
echo "hello, $1"Bash
cat > check.sh <<'EOF'
#!/bin/bash
set -euo pipefail
if [ $# -lt 1 ]; then
echo "usage: $0 <name>" >&2
exit 2
fi
echo "hello, $1"
EOF
bash check.sh 2>/dev/null || echo "exit=$?"
bash check.sh AliceOutput
exit=2
hello, Alice${1:?message} is terser: it aborts when the parameter is empty. ${1:-default} supplies a default, ${1:?} makes it mandatory.位置参数
Bash
#!/bin/bash
echo "script: $0"
echo "first : $1"
echo "second: $2"
echo "count : $#"Bash
cat > args.sh <<'EOF'
#!/bin/bash
echo "script: $0"
echo "first : $1"
echo "second: $2"
echo "count : $#"
EOF
bash args.sh alpha betaOutput
script: args.sh
first : alpha
second: beta
count : 2| 变量 | 含义 |
|---|---|
$0 | 脚本名 |
$1…$9 | 第 1..9 个参数 |
${10} | 第 10 个起必须加花括号 |
$# | 参数个数 |
$@ | 所有参数,各自独立 |
$* | 所有参数拼成一个字符串 |
$$ | 当前 shell 的 PID |
$? | 上一条命令的退出码 |
$@ 与 $*
Bash
#!/bin/bash
echo "with @:"
for a in "$@"; do echo " [$a]"; done
echo "with *:"
for a in "$*"; do echo " [$a]"; doneBash
cat > atstar.sh <<'EOF'
#!/bin/bash
echo "with @:"
for a in "$@"; do echo " [$a]"; done
echo "with *:"
for a in "$*"; do echo " [$a]"; done
EOF
bash atstar.sh "a b" cOutput
with @:
[a b]
[c]
with *:
[a b c]差别就在引号里:"$@" 展开成两个词 a b 和 c,"$*" 展开成一个词 a b c。所以传参给别的命令时永远用 "$@"。
shift
Bash
#!/bin/bash
echo "before: $# args, first=$1"
shift
echo "after : $# args, first=$1"Bash
cat > shift.sh <<'EOF'
#!/bin/bash
echo "before: $# args, first=$1"
shift
echo "after : $# args, first=$1"
EOF
bash shift.sh one two threeOutput
before: 3 args, first=one
after : 2 args, first=two参数校验
Bash
#!/bin/bash
set -euo pipefail
if [ $# -lt 1 ]; then
echo "usage: $0 <name>" >&2
exit 2
fi
echo "hello, $1"Bash
cat > check.sh <<'EOF'
#!/bin/bash
set -euo pipefail
if [ $# -lt 1 ]; then
echo "usage: $0 <name>" >&2
exit 2
fi
echo "hello, $1"
EOF
bash check.sh 2>/dev/null || echo "exit=$?"
bash check.sh AliceOutput
exit=2
hello, Alice${1:?message} 更简洁:参数为空时直接报错退出。${1:-default} 是给默认值,${1:?} 是强制要求。