$ 符号的功能 链接到标题

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 也支持逻辑表达式的与、或,如下图所示:

H7c3Xp

对于“或”运算,如果左侧的结果已经为真,那么就不会再去计算右侧的结果,因此 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