Skip to content

介绍

shell 编程中,双引号会展开变量和命令,特殊字符保留;单引号不展开任何内容,全部原样输出。

$(…):命令替换,将 中命令的输出 (stdout) 插入到该位置

bash
# 格式化输出日期 如 20240228
date +%Y%m%d
bash
# Go Module 镜像/代理
export GOPROXY=https://goproxy.cn,direct

# 安装 shfmt
go install mvdan.cc/sh/v3/cmd/shfmt@latest

浮点数运算:

bash
# scale 保留小数位数
echo "scale=4; 0.05*0.1" | bc

c=$(echo "5.01-4*2.0" | bc); echo $c

c=$(awk 'BEGIN { print 7.01*5-4.01 }'); echo $c

字符串大小写转换

bash
# Bash 4.0 及更高版本中有效
${variable,,}       # 将字符串转换为小写
${variable,}        # 首字母小写
${variable^^}       # 大写
${variable^}        # 首字母大写
bash
# 将字符串转换为小写
echo "Hello World" | tr '[:upper:]' '[:lower:]'
echo "HELLO WORLD" | awk '{ print tolower($0) }'

# 大写
echo "hello world" | tr '[:lower:]' '[:upper:]'
echo "hello world" | awk '{ print toupper($0) }'

shellcheck 在线版本:ShellCheck – shell script analysis tool

bash
shellcheck script.sh

-s             # 指定方言 sh, bash, dash, ksh, busybox
-f              # 指定输出格式 checkstyle, diff, gcc, json, json1, quiet, tty
bash
# 打印格式化后的内容,不修改文件内容
shfmt script.sh
# 将格式化后的内容写入文件
shfmt -w script.sh

-i n            # 指定缩进
-mn             # 启用最小化模式,通常删除不必要的空格和换行符
-ln             # 指定方言 bash/posix/mksh/bats

set -xset -e:在执行脚本时进行调试和错误处理。

set -x:在执行 Shell 脚本时,打印出将要执行的每一条命令及其参数。 set -e:在脚本执行过程中,遇到错误时立即退出。默认情况下,Bash Shell 会继续执行下去,忽略非零的返回值。


参考资料


语法

运行脚本

  • 脚本以 #! 行开头,指定解释器
bash
#!/bin/bash

...
  • 运行脚本
bash
# 方式 1
bash script.sh

# 方式 2
chmod +x script.sh  # 文件颜色变绿
./script.sh

变量

  • 定义变量:变量名和等号之间不能有空格
  • 使用变量:在变量名前面加美元符号 $;可在变量名外面添加花括号,帮助解释器识别变量边界
  • 删除变量:unset
bash
var="letter"

echo $var
echo ${var}

unset var
  • 特殊变量
    • $? :用于测试命令执行结果(执行成功会返回 0,失败返回非零数值)
变量含义
$0当前脚本文件名
$#参数个数

命令替换:执行命令并将其输出作为另一个命令的参数;使用反引号 `` 或者 $(command)

bash
# 方式 1
today=`date`
echo "Today is $today"

# 方式 2
today=$(date)
echo "Today is $today"

注释

  • 单行注释
bash
# comment
  • 多行注释
bash
: '
comment 1
comment 2
'

打印输出

  • echo 自动添加换行符, printf 不会
bash
echo  # 输出一行空行

echo -n  # 不自动换行

echo -e  # 执行转义字符

字典

关联数组

bash
declare -A sounds

sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"

函数

bash
#!/bin/bash

func() { 
	echo "hello $1" 
}

fun "world"

输出固定位数

bash
printf "ICET-Traing-No-%05d\n" 123  #输出5位数,00123

数组

数组合并

bash
array1=()
array2=()
array_merge=(${array1[*]} ${array2[*]})

数组

bash
# 用括号来表示数组,数组元素用"空格"符号分割开
array_name=(value0 value1 value2 value3)

# 获取数组元素
echo ${array_name} # 直接打印数组名,读取的是数组第一个元素
echo ${array_name[0]} # 读取数组第一个元素
echo ${array_name[*]} # 读取数组所有元素
echo ${array_name[@]} # 读取数组所有元素

# 获取数组长度
echo ${#array_name[*]}
echo ${#array_name[@]}
echo ${#array_name[0]} # 获取单个元素的长度

整数型变量自增

bash
# 定义整型变量
a=1
echo $a

# 方式1
let a++
echo $a

# 方式2
let a+=1
echo $a
bash
# 判断字符串是否相等;下面两者等价
a="1"
b="1"

if [ $a = $b ];then
echo "="
fi

if [ $a == $b ];then
echo "=="
fi
bash
-eq # 等于
-ne # 不等于
-gt # 大于
-ge # 大于等于
-lt # 小于
-le # 小于等于
! # 取非
-a # and,左右条件两者都成立
-o # or,左右条件任意一条成立

参数传递

可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n

  • $0 为执行的文件名
  • $# 为传递到脚本的参数个数
  • $* 为引用所有参数;用双引号时,” * “ 等价于 “1 2 3”(传递了一个参数)
  • $@ 为引用所有参数;用双引号时,“@” 等价于 “1” “2” “3”(传递了三个参数)
bash
#!/bin/bash

echo "script_name: $0"
echo "para1: $1"
echo "para2: $2"
echo "para3: $3"
 ​
# bash test.sh {2..4}

条件语句

if 条件语句

bash
a=10
b=20

# then 可以另起一行,删除分号
if [ $a == $b ]; then 
    echo "a is equal to b"
elif [ $a -gt $b ]; then
	echo "a is greater to b"
fi

写成一行

bash
a=10; b=20; if [ $a == $b ]; then echo "a is equal to b"; fi

case 分支语句:可用到命令行解析中

bash
grade="B"

# A B C 中的双引号可删除
# ;; 可以另起一行
# 右括号 ) 前面的内容与后面的命令之间可以另起一行
case $grade in 
    "A") echo "Very Good!";;
    "B") echo "Good!";;
    "C") echo "Come On!";;
    *) 
        echo "You Must Try!"
        echo "Sorry!";;
esac

for 循环

bash
# do 可以另起一行,删除分号
for var in list; do
	command
done

示例:

bash
for i in 1 2 3 4 5; do 
    echo "The value is $i"
done

for i in {1..5}; do 
    echo "The value is $i"
done

for i in {1..5..2}; do 
    echo "The value is $i"
done

for i in $(seq 1 2 5); do 
    echo "The value is $i"
done

# 小数序列
for i in $(seq 1 0.2 2); do 
    echo "The value is $i"
done

# C 语言风格
for((i=1; i<=20; i++)); do
    echo "The value is $i"
done
bash
# 99 乘法表
for i in {1..9}; do
	for j in $(seq $i); do 
	    echo -n -e "$j*$i=$[j*i]\t"
    done
	echo
done

读取文件的每一行

bash
cat file.txt | while read line; do 
	echo $line
done

整数条件

字符串条件

-n - 可用于检测一个变量是否已经定义并且值不为空

bash
[[ -z STR ]]    # 空字符串  可检查环境变量是否被定义
[[ -n STR ]]    #  非空字符串 
[[ STR == STR ]]    #  相等 
[[ STR = STR ]]    #  相等(同上)
[[ STR =~ STR ]]    # 正则表达式

bc:基础计算器(basic calculator)

文件条件

bash
-f  # 文件
-d  # 目录
-e  # 文件/目录是否存在

test 命令

原生 bash 不支持简单的数学运算,可通过 expr 命令(最常用)来实现

bash
# 表达式和运算符之间要有空格  
# 完整的表达式要被 ` ` 包含  
val=`expr 2 + 2`  
 ​  
# 乘号(*)前边必须加反斜杠(\)才能实现乘法运算  
val=`expr $a \* $b`

字符串切片 ${str:1:4}

bash
# 删除变量;变量被删除后不能再次使用
unset name

# 获取字符串长度
echo ${#str}
echo ${#str[0]}

重定向

bash
python hello.py > output.txt   # 标准输出到(文件) 
python hello.py >> output.txt  # 标准输出到(文件),追加 
python hello.py 2> error.log   # 标准错误到(文件) 
python hello.py 2>&1           # 标准错误到标准输出 
python hello.py 2>/dev/null    # 标准错误到(空null) 
python hello.py &>/dev/null    # 标准输出和标准错误到(空null) 
python hello.py < foo.txt      # 将 foo.txt 提供给 python 的标准输入

数据处理相关工具

参考资料

《命令行中数据科学》

GitHub - jeroenjanssens/data-science-at-the-command-line: Data Science at the Command Line

100+ Command Line Tools for Data Visualization / Alex Garcia | Observable

Linux数据处理命令工具

对算术表达式的值进行引用时需要使用 [](()),两者作用相同

shell 脚本常用的环境变量

RANDOM

bash
$RANDOM     # 生成0~32767之间的随机数
$[RANDOM%num]     # 生成0~num之间的随机数;对算术表达式的值进行引用时需要使用[]

https://shellscript.readthedocs.io/zh_CN/latest/2-library/0-commonvar/index.html#randoml

shell,小数运算并取整

bash
# 10/3 运算结果的整数部分
# -d "." 参数指定使用小数点作为分隔符,-f1 参数指定提取第一个字段,也就是整数部分
echo "scale=2; 10/3" | bc | cut -d "." -f1

sed 进行多次替换:用 ; 号或者 -e 参数

注意,使用分号将多个替换命令串联起来时,每个命令的末尾不能有空格,否则可能导致语法错误

bash
# 两者等价
# s/[A-Z]/\L&/g 表示将所有大写字母转换为小写字母。
# 这个命令使用正则表达式 [A-Z] 匹配所有大写字母,\L& 表示将匹配到的字符串转换为小写字母,
# & 表示引用整个匹配模式的字符串。这个命令也使用 g 选项表示替换所有匹配的字符串
echo "HELLO WORLD" | sed -e 's/ /_/g; s/[A-Z]/\L&/g'

echo "HELLO WORLD" | sed -e 's/ /_/g' -e 's/[A-Z]/\L&/g'

seq 111 | sed -n 's/\([[:digit:]]\)\1/&/p':从 1 到 111 的数字序列中,找出有连续重复数字的数字,并将其替换为相同数字两次组成的字符串

  • n 选项表示禁止默认输出,只输出经过处理后的数据。
  • s 命令用于替换字符串,后面跟着替换规则。
  • /…/ 之间是正则表达式,表示要匹配的字符串模式。
  • \(…\) 是用于捕获匹配的字符串的分组语法。
  • [[:digit:]] 是一个 POSIX 字符类,表示匹配数字字符。
  • \1 表示对第一个分组进行反向引用,即匹配到的重复数字。
  • & 表示引用整个匹配模式的字符串,即替换为相同数字两次组成的字符串。
  • /p 表示仅输出经过处理后的行,忽略未经处理的行。

格式化输出 bash date 命令

https://www.tutorialkart.com/bash-shell-scripting/bash-date-format-options-examples/

bash
date
# Sun Mar 12 00:32:26 CST 2023

date +"%Y/%m/%d %H:%M:%S"
# 2023/03/12 00:32:33

bash sleep 命令

https://www.tutorialkart.com/bash-shell-scripting/bash-sleep/

bash
sleep 3s
sleep 3
sleep m
sleep h
sleep d

其他

重复输出字符:How to repeat a character 'n' times in Bash - nixCraft

bash
# 重复输出等号
printf '==%.0s' {1..20}; printf '\n'

# 定义函数
repeat(){
	for i in {1..90}; do echo -n "$1"; done
}

repeat '-'; echo
repeat '='; echo