编写 Linux bash shell 脚本时,经常会用到 $0、$1、$2、${n}、$#、$@、$*、$?、 $_、$!、$$ 等参数,下面具体说明这些参数的含义。

假设执行 ./test.sh a b c 这样一个命令,则可以使用下面的参数来获取一些值:

示例:./test.sh a b c  或者  sh test.sh a b c

$0 对应 "./test.sh" 这个值。如果执行的是 ./work/test.sh, 则对应 ./work/test.sh 这个值,而不是只返回文件名本身的部分。

 

$1 会获取到第1个参数 a,即 $1 对应传给脚本的第一个参数

$2 会获取到第2个参数 b,即 $2 对应传给脚本的第二个参数

$3 会获取到第3个参数 c,即 $3 对应传给脚本的第三个参数

$4、$5、$n 等参数的含义依此类推,且从第10个位置参数开始,必须使用花括号括起来,如:${10}

 

$# 会获取到参数的个数 3,对应传入脚本的参数个数,即(a b c)共3个参数,统计的参数不包括 $0(shell 脚本本身)。

$@ 会获取到 "a" "b" "c",也就是所有参数的列表,数组格式 以 "参数1" "参数2" … "参数n" 形式保存所有参数,不包括 $0。这是将参数传递给其它程序的最佳方式,因为它会保留所有内嵌在每个参数里的任何空格分隔

$* 也会获取到 "a" "b" "c", 其值和 $@ 相同,是一整个字符串 "参数1 参数2 … " 形式保存所有参数,不包括 $0。

但 "$*" 和 "$@" 有所不同:"$@" 会得到一个字符串参数数组,而 "$*" 把所有参数合并成一个字符串。

 

$? 可以获取到执行 ./test.sh a b c 命令后的返回值。在执行一个前台命令后,可以立即用 $? 获取到该命令的返回值。

该命令可以是系统自身的命令,可以是 shell 脚本,也可以是自定义的 bash 函数,返回 0 表示成功;其它值,则是失败。

 

$_  在此之前执行的命令或脚本的最后一个参数

$!  上一个命令的PID

$$:获取当前的shell进程号PID

 

简单总结

$# 表示位置参数的数量
$* 表示所有位置参数的内容
$? 表示命令执行后返回的状态    (执行成功 返回0  执行不成功  返回非0)
$$ 表示当前进程的进程号 希望打开一个进程后不再打开另一个(/proc/<PID>)
$! 表示后台运行的最后一个进程号
$0 表示当前的进程名

 

 

"$*" 和 "$@" 参数值

假设有一个 shell_test_param.sh 脚本,内容如下:

vim shell_test_param.sh

#!/bin/bash
#
# mimvp.com  2010.12.22

echo "--- test string $* ---"
for arg in "$*";
do
    echo "arg *** : " $arg
done

echo "--- test array $@ ---"
for arg in "$@";
do
    echo "arg @@@ : " $arg
done

这个脚本分别遍历 "$*" 和 "$@" 扩展后的内容,并打印出来。

执行 sh shell_test_param.sh,结果如下:

$ sh shell_test_param.sh I love mimvp.com
--- test string I love mimvp.com ---
arg *** :  I love mimvp.com
--- test array I love mimvp.com ---
arg @@@ :  I
arg @@@ :  love
arg @@@ :  mimvp.com

可以看到

"$*" 只产生一个字符串,for 循环只遍历一次。

"$@" 产生了多个字符串组成的数组,for 循环遍历多次,是一个字符串参数数组。

 

注意

如果传入的参数多于 9 个,则不能使用 $10 来引用第 10 个参数,而是要用 ${10} 来引用。即,需要用大括号{}把大于 9 的数字括起来。

例如,${10} 表示获取第 10 个参数的值,写为 $10 获取不到第 10 个参数的值。

实际上,$10 相当于 ${1}0,也就是先获取 $1 的值,后面再跟上 0,如果 $1 的值是 "first",则 $10 的值是 "first0"。

示例:

vim shell_test_param10.sh 

#!/bin/bash
#
# mimvp.com in 2010.12.12

echo $0
echo $1
echo $2
echo $3
echo $4
echo $5
echo $6
echo $7
echo $8
echo $9
echo $10
echo ${10}
echo $11
echo ${11}

运行结果:

$ sh shell_test_param10.sh a b c d e f g h i j k l m n
shell_test_param10.sh
a
b
c
d
e
f
g
h
i
a0
j
a1
k

可见,$0 表示shell脚本 ;$10 表示 $1 = ${1}0 = a0,${10} 才是j ;同理 $11 与 ${11}

 

查看 man bash 里面对位置参数(positional parameters)的说明如下:

Positional Parameters

A positional parameter is a parameter denoted by one or more digits, other than the single digit 0.

Positional parameters are assigned from the shell's arguments when it is invoked, and may be reassigned using the set builtin command. Positional parameters may not be assigned to with assignment statements. The positional parameters are temporarily replaced when a shell function is executed.

When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces.

即,最后一句提到,当位置参数由多位数字组成时,需要用大括号 {} 把多位数字括起来。

 

 

$#​  参数个数

在 bash 中,可以使用 $# 来获取传入的命令行或者传入函数的参数个数

要注意的是,$# 统计的参数个数不包括脚本自身名称或者函数名称。

例如,执行 ./a.sh a b,则 $# 是参数个数 2(即 a b ,不包含shell脚本 ./a.sh),因此不是 3。

查看 man bash 的说明如下:

Special Parameters

# Expands to the number of positional parameters in decimal.

可以看到,$# 实际上是扩展为位置参数(positional parameters)的个数,统计的参数不包括 $0。

 

 

$? 执行的返回值

1、当执行系统自身的命令时,$? 对应这个命令的返回值,0为成功,非0为失败

$ echo "I love mimvp.com"
I love mimvp.com
$ echo $?
0
$ echo ${mimvp.com}
-bash: ${mimvp.com}: bad substitution
$ echo $?
1
r$ 
$ sh shell_test_param.sh I love mimvp.com
--- test string I love mimvp.com ---
arg *** :  I love mimvp.com
--- test array I love mimvp.com ---
arg @@@ :  I
arg @@@ :  love
arg @@@ :  mimvp.com
$ echo $?
0

如上,执行 echo、sh xxx.sh 都是成功的,$? 返回值都是 0

执行 echo ${mimvp.com} 提示错误,未定义变量值,返回错误,$? 返回值是 1 (非0值)

 

2、当执行 shell 脚本时,$? 对应该脚本调用 exit 命令返回的值

如果没有主动调用 exit 命令,默认返回为 0

vim shell_test_return.sh

#!/bin/bash
#
# mimvp.com in 2010.12.12

args_str=$*
args_arr=$@
args_num=$#

if (( ${args_num} > 0 )); then
    echo "args_num: ${args_num}"
    exit 0
else
    echo "no args"
    exit 1
fi

执行结果:

$ sh shell_test_return.sh I love mimvp.com
args_num: 3
$ echo $?
0
$ sh shell_test_return.sh 
no args
$ echo $?
1

代码说明:

有参数传入(参数个数大于0),成功返回0;无参数传入,失败返回1

 

3、当执行自定义的 bash 函数时,$? 对应该函数调用 return 命令返回的值

如果没有主动调用 return 命令,默认返回为 0

vim shell_test_return.sh

#!/bin/bash
#
# mimvp.com in 2010.12.12

args_str=$*
args_arr=$@
args_num=$#


function test_return() {
    if (( ${args_num} > 0 )); then
        echo "args_num: ${args_num}"
        return 0
    else
        echo "no args"
        return 1
    fi
}

test_return
echo $?

执行结果:

$ sh shell_test_return.sh I love mimvp.com
args_num: 3
$ sh shell_test_return.sh I love mimvp.com
args_num: 3
0
$ sh shell_test_return.sh 
no args
1

代码说明:

有参数传入(参数个数大于0),成功 return 返回0;无参数传入,失败return 返回1

 

 

$_、$!、$$

$_  在此之前执行的命令或脚本的最后一个参数

$!  上一个命令的PID

$$:获取当前的shell进程号PID

示例代码:

vim shell_test_return.sh

#!/bin/bash
#
# mimvp.com in 2010.12.12

args_str="$*"
args_arr="$@"
args_num="$#"


function test_return() {
    if (( ${args_num} > 0 )); then
        echo "args_num: ${args_num}"
        echo "args_str: ${args_str}"
        echo "args_arr: ${args_arr}"

#        for arg in "$*"
        for arg in ${args_str}
        do
            echo "arg *** ${arg}"
        done

        for arg in ${args_arr}
        do
            echo "arg @@@ ${arg}"
        done

        return 0
    else
        echo "no args"
        return 1
    fi
}

echo "------"
echo '$_' "$_"


echo '$!' "$!"
echo '$$' "$$"
echo '$_' "$_"


test_return  a b c
echo '$_' "$_"
echo $?
echo '$_' "$_"


echo '$!' "$!"
echo '$$' "$$"
echo '$_' "$_"

执行结果:

$ sh shell_test_return.sh I love mimvp.com 
------
$_ ------
$! 
$$ 19164
$_ 19164
args_num: 3
args_str: I love mimvp.com
args_arr: I love mimvp.com
arg *** I
arg *** love
arg *** mimvp.com
arg @@@ I
arg @@@ love
arg @@@ mimvp.com
$_ c
0
$_ 0
$! 
$$ 19164
$_ 19164

代码说明:

$_  在此之前执行的命令或脚本的最后一个参数,例如:test_return a b c 的最后一个参数 $_ c ,  $$ 19164 的最后一个参数  $_ 19164, 

$!  上一个命令的PID,似乎没效果,总是空

$$:获取当前的shell进程号PID,例如:$$ 19164

上面,需要重点说明一下,for arg in ${args_str}    for arg in ${args_arr} 返回的都是数组,原因是 args_str 和 args_arr 是空格隔开的字符串,类似于 $@ 格式了,若要当成一个整体字符串出来,就把 for arg in ${args_str} 改成 for arg in "$*"

 

 

参考推荐:

shell 基础知识

shell命令curl 检测代理是否可用

Shell 提取文件路径中的文件名、后缀、目录 (推荐

Linux shell 局部变量与全局变量

Linux 之 shell 比较运算符

Linux Shell 函数返回值

Linux curl 命令模拟 POST/GET 请求

Linux Make(Makefile)由浅入深的学习与示例剖析

shell if语句 示例:文件或目录是否存在或有执行权限

linux实现两个文件内容相加

Linux cut 命令

linux 命令快捷键

Linux Shell 常用命令与目录分区

Linux shell 脚本通过expect实现自动输入密码

nohup、&、disown、setsid、screen、jobs 后台运行命令区别

cp、tar 命令排除文件和子目录

zip、tar 命令加密和解密压缩文件

Linux下tar、bz、gz等压缩包的压缩和解压