Last Updated: 2023-06-24 13:54:11 Saturday
-- TOC --
Bash命令行有一些特殊变量,本文将它们汇总学习。看见$
符号,就是Bash变量哈。
表示上一个命令的exit code
。一般0表示成功,其它表示各种失败或错误。
自己编写shell脚本,可通过exit命令输出这个值,比如:exit 0
或exit 1
。Python的sys.exit也是输出这个值。C语言main函数中return的值也是的。
注意,exit code的取值范围是
0-255
,不管exit带的值是多少,最后通过echo $?都只能拿到低位的unsigned byte
!因此,代码中出现exit一个负数,基本上就是一个错误,exit一个超过255的正数,也是错误。
windows下获取exit code的方法
start /wait something.exe
echo %errorlevel%
表示输入脚本的参数。
$0
表示脚本文件名;
从$1
开始,分别按顺序对应命令的一个参数。
进入脚本所在目录的小技巧:
dname=$(dirname $0)
cd $dname
# ...
cd -
$#
,arguments number表示参数的总的数量。
这两个变量都表示全部参数,但在使用时有些不同之处。
当 $*
和 $@
没有被双引号包围时,它们之间没有任何区别,都是将接收到的参数看做一份数据,彼此之间以空格来分隔。
但是当它们被双引号""
包含时,就会有区别了:
$*
会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。$@
仍然将每个参数看作一份独立的数据,彼此之间是独立的。下面是我写过的一个bug,整理了一下,大家可以看出这两个符号之间的差异:
首先,一段python,通过命令行获取一个值(nargs=argparse.REMAINDER),然后打印出来:
$ cat arg.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('cmd', nargs=argparse.REMAINDER, help='...')
args = parser.parse_args()
print(args.cmd)
然后,开始测试:
$ set 1 2 3 4
$ bash -c "python3 arg.py $@"
['1']
$ bash -c "python3 arg.py $*"
['1', '2', '3', '4']
看出区别来了吧......这个bug消耗了几个小时的生命。$*只传入一个表示全部参数的$1,$@的$1只有1。
下面这个测试会更明显:
$ cat arg.sh
function echo_arg() {
echo '$1' $1
echo '$2' $2
echo '$3' $3
}
echo test '$@'
echo_arg "$@"
echo test '$*'
echo_arg "$*"
$ bash arg.sh 1 2 3 4
test $@
$1 1
$2 2
$3 3
test $*
$1 1 2 3 4
$2
$3
坑
使用"$*"
展开的命令字符串带单引号,一定要使用bach -c
执行。
$ cat t.sh
set -x
echo "$*"
echo "$@"
$ bash t.sh a b 1 2
+ echo 'a b 1 2'
a b 1 2
+ echo a b 1 2
a b 1 2
$$
表示当前进程ID。
看名字就知道,这是取当前进程的父进程。
$ echo $$
11919
$ echo $PPID
11917
$!
表示shell最后执行的后台进程的pid。常常与wait命令配合,等到某个后台进程执行完毕。
$-
表示当前shell参数。
#!/bin/bash
echo "Starting program at $(date)" # Date will be substituted
echo "Running program $0 with $# arguments with pid $$"
for file in "$@"; do
grep foobar "$file" > /dev/null 2> /dev/null
# When pattern is not found, grep has exit status 1
# We redirect STDOUT and STDERR to a null register since we do not care about them
if [[ $? -ne 0 ]]; then
echo "File $file does not have any foobar, adding one"
echo "# foobar" >> "$file"
fi
done
Entire last command, including arguments.
!!
表示上一条命令,包括所有参数。
A common pattern is to execute a command only for it to fail due to missing permissions; you can quickly re-execute the command with sudo by doing sudo !!
$_
- Last argument from the last command.
$ echo a b c d 1234
a b c d 1234
$ echo $_
1234
$ echo $_
1234
有两个特殊的bash数组
这个是特殊的数组。当使用source命令引入一个脚本文件的时候,$0
不会改变,还是bash或者父脚本的名称,此时就要通过BASH_SOURCE
来获取sourced script name!
先感受一下这个变量:
$ cat test.sh
echo ${BASH_SOURCE[@]}
echo $0
$ bash test.sh
test.sh
test.sh
$ . test.sh
test.sh
bash
通过source执行test.sh,查看$0和BASH_SOURCE的值。
当sourced script里面,继续source其它srcipt的时候,BASH_SOURCE就像一个函数调用栈一样的数组:
$ cat test.sh
echo ${BASH_SOURCE[@]}
echo $0
. kk.sh
$ cat kk.sh
echo ${BASH_SOURCE[@]}
echo $0
$ bash test.sh
test.sh
test.sh
kk.sh test.sh
test.sh
$ . test.sh
test.sh
bash
kk.sh test.sh
bash
跟BASH_SOURCE类似的特殊数组。
$ cat tf.sh
function f1() {
echo ${FUNCNAME[@]}
}
function f2() {
echo ${FUNCNAME[@]}
f1
}
function f3() {
echo ${FUNCNAME[@]}
f2
}
f3
$ bash tf.sh
f3 main
f2 f3 main
f1 f2 f3 main
$ . tf.sh
f3 source
f2 f3 source
f1 f2 f3 source
本文链接:https://cs.pynote.net/sf/linux/shell/202201044/
-- EOF --
-- MORE --