$
符号的功能
链接到标题
Shell 中,$
符号可以与数字或者其他符号组合在一起表示特殊的值或者变量,如下:
#!/bin/bash
echo $0 # $0 用于获取当前脚本文件名名称
echo "The first parameter: $1" # $1 表示第一个参数
echo "The eleventh parameter: ${11}2"
echo "The eleventh parameter: ${11}x"
echo "The eleventh parameter: $11x"
echo "The eleventh parameter: $12"
tmp="hello"
echo "$tmp world"
将以上脚本文件命名为 test.sh
并执行 bash test.sh 1 2 3 4 5 6 7 8 9 10 13 14
,输出如下:
test.sh
The first parameter: 1
The eleventh parameter: 132
The eleventh parameter: 13x
The eleventh parameter: 11x
The eleventh parameter: 12
hello wolrd
这是因为,只有 $n
才能表示第 n
个参数(n
为单个数字),如果想表示第 11
个参数,就必须使用 ${11}
(加上大括号)来表示,bash 会将 $12
处理为名为 12
的变量。
此外,$#
表示参数的个数,类似于程序中的 argc
,$@
表示所有参数的列表,在 bash 或者 zsh 中,$_
表示上一个命令的最后一个参数,而 !!
则表示执行的上一条命令,$?
表示上一个命令的返回状态,为 0 表示命令成功执行。
$$
表示当前进程的 pid。
例如:
mkdir tmp
cd $_ # 进入到了 tmp 目录
mkdir test
sudo !! # 这里就是表示执行 sudo mkdir test
shell 中定义函数与使用 链接到标题
执行 nvim mcd.sh
,将其内容修改为如下:
mcd () {
mkdir -p "$1"
cd "$1"
}
然后保存,再执行 source mcd.sh
,即在当前 shell 执行了 mcd.sh
,而 ./mcd.sh
会创建一个子 shell 来执行,执行了 source mcd.sh
之后,当前 shell 中就有一个我们定义的名为 mcd
的函数了,在当前 shell 中,我们就可以使用 mcd
命令来创建并进入指定的目录了:
注意,这里不能用
fish
,必须用bash
或者兼容bash
的 shell 例如fish
。
source mcd.sh
mcd arm # 将进入创建的名为 arm 的目录中
逻辑表达式 链接到标题
shell 也支持逻辑表达式的与、或,如下图所示:
对于“或”运算,如果左侧的结果已经为真,那么就不会再去计算右侧的结果,因此 echo "Oops fail"
无输出,“与”运算的原理相同。
变量 链接到标题
当使用双引号来表示字符串时,shell 会对引号内的内容进行变量与命令替换,它将 ()
包裹的内容视为命令,将 {}
包裹的内容视为变量,并进行替换,将 ()
包裹的内容替换为输出结果,将 {}
包裹的内容替换为变量的值。
zwyyy in 🌐 armbian in ~/missing-semester/arm
❯ foo=$(pwd)
zwyyy in 🌐 armbian in ~/missing-semester/arm
❯ echo $foo
/home/zwyyy/missing-semester/arm
zwyyy in 🌐 armbian in ~/missing-semester/arm
❯ echo "We are in $(pwd)"
We are in /home/zwyyy/missing-semester/arm
zwyyy in 🌐 armbian in ~/missing-semester/arm
❯ echo 'We are in $(pwd)'
We are in $(pwd)
zwyyy in 🌐 armbian in ~/missing-semester/arm
❯ echo "we are in ${foo}"
we are in /home/zwyyy/missing-semester/arm
以下是一个使用到了前面所述的知识点的脚本:
#! /bin/bash
echo "Starting program at $(date)"
echo "Running program $0 with $# arguments with pid $$"
for file in "$@"; do
grep foobar "$file" > /dev/null 2> /dev/null
if [[ "$?" -ne 0 ]]; then
echo "File $file does not have any foobar, adding one"
echo "# foorbar" >> "$file"
fi
done
其中,`grep foobar “$file” > /dev/null 2> /dev/null
shell 的一些缩写 链接到标题
convert image.{png,jpg}
等价于 convert image.png image.jpg
;
而 touch foo{,1,2,10}
等价于 touch foo foo1 foo2 foo10
;
而 touch project{1,2}/src/test/test{1,2,3}.py
等价于 touch project1/src/test/test1.py project1/src/test/test2.py project1/src/test/test3.py project2/src/test/test1.py project2/src/test/test2.py project2/src/test/test3.py
。
与 Python 交互的 shell 脚本 链接到标题
#!/usr/bin/python3
# test.py
import sys
for arg in reversed(sys.argv[1:]):
print(arg)
# foobar
其中,第一行注释 #!/usr/bin/python3
被称为 shebang
,用于指定 python 脚本该由哪个解释器运行。
我们当然可以通过
python test.py
来运行该脚本,此时不需要shebang
,但假设我们希望通过./test.py
来运行,那么久需要shebang
来告诉 shell,应该使用哪个 python 解释器来运行该脚本。
将 #!/usr/bin/python3
替换为 #!/usr/bin/env python3
能增强程序的可移植性,/usr/bin/env
是一个 Unix 程序,它会查找 python3
解释器的路径并执行它,因此,对于我的电脑来说,#!/usr/bin/env python3
就相当于 #!/usr/bin/env python3
。