Shell 编程
# 介绍
shell 编程中,双引号会展开变量和命令,特殊字符保留;单引号不展开任何内容,全部原样输出。
$(…)
:命令替换,将 …
中命令的输出 (stdout) 插入到该位置
# 格式化输出日期 如 20240228
date +%Y%m%d
# Go Module 镜像/代理
export GOPROXY=https://goproxy.cn,direct
# 安装 shfmt
go install mvdan.cc/sh/v3/cmd/shfmt@latest
- [ ] shell 命令行解析:getoptions (opens new window)、argparse-bash (opens new window)
浮点数运算:
- bash 不支持浮点运算,如果需要进行浮点运算,需要借助 bc, awk 处理;linux shell 实现 四则运算(整数及浮点) 简单方法 - 程默 - 博客园 (opens new window)
# 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 4.0 及更高版本中有效
${variable,,} # 将字符串转换为小写
${variable,} # 首字母小写
${variable^^} # 大写
${variable^} # 首字母大写
# 将字符串转换为小写
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 (opens new window)
shellcheck script.sh
-s # 指定方言 sh, bash, dash, ksh, busybox
-f # 指定输出格式 checkstyle, diff, gcc, json, json1, quiet, tty
# 打印格式化后的内容,不修改文件内容
shfmt script.sh
# 将格式化后的内容写入文件
shfmt -w script.sh
-i n # 指定缩进
-mn # 启用最小化模式,通常删除不必要的空格和换行符
-ln # 指定方言 bash/posix/mksh/bats
set -x
和 set -e
:在执行脚本时进行调试和错误处理。
set -x
:在执行 Shell 脚本时,打印出将要执行的每一条命令及其参数。
set -e
:在脚本执行过程中,遇到错误时立即退出。默认情况下,Bash Shell 会继续执行下去,忽略非零的返回值。
# 参考资料
- 速查表:Bash 备忘清单 & bash cheatsheet & Quick Reference (opens new window)
- shell脚本基础 | cherry (opens new window)
- shell 脚本案例:GitHub - jacobproject/Shell_Scripts: Shell Scripts examples (opens new window)
# 语法
# 运行脚本
- 脚本以
#!
行开头,指定解释器
#!/bin/bash
...
- 运行脚本
# 方式 1
bash script.sh
# 方式 2
chmod +x script.sh # 文件颜色变绿
./script.sh
# 变量
- 定义变量:变量名和等号之间不能有空格
- 使用变量:在变量名前面加美元符号
$
;可在变量名外面添加花括号,帮助解释器识别变量边界 - 删除变量:
unset
var="letter"
echo $var
echo ${var}
unset var
- 特殊变量
$?
:用于测试命令执行结果(执行成功会返回 0,失败返回非零数值)
变量 | 含义 |
---|---|
$0 | 当前脚本文件名 |
$# | 参数个数 |
命令替换:执行命令并将其输出作为另一个命令的参数;使用反引号 `` 或者 $(command)
# 方式 1
today=`date`
echo "Today is $today"
# 方式 2
today=$(date)
echo "Today is $today"
# 注释
- 单行注释
# comment
- 多行注释
: '
comment 1
comment 2
'
# 打印输出
echo
自动添加换行符,printf
不会
echo # 输出一行空行
echo -n # 不自动换行
echo -e # 执行转义字符
# 字典
关联数组
declare -A sounds
sounds[dog]="bark"
sounds[cow]="moo"
sounds[bird]="tweet"
sounds[wolf]="howl"
# 函数
#!/bin/bash
func() {
echo "hello $1"
}
fun "world"
输出固定位数
printf "ICET-Traing-No-%05d\n" 123 #输出5位数,00123
# 数组
数组合并
array1=()
array2=()
array_merge=(${array1[*]} ${array2[*]})
数组
# 用括号来表示数组,数组元素用"空格"符号分割开
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]} # 获取单个元素的长度
整数型变量自增
# 定义整型变量
a=1
echo $a
# 方式1
let a++
echo $a
# 方式2
let a+=1
echo $a
# 判断字符串是否相等;下面两者等价
a="1"
b="1"
if [ $a = $b ];then
echo "="
fi
if [ $a == $b ];then
echo "=="
fi
-eq # 等于
-ne # 不等于
-gt # 大于
-ge # 大于等于
-lt # 小于
-le # 小于等于
! # 取非
-a # and,左右条件两者都成立
-o # or,左右条件任意一条成立
# 参数传递
可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n
;
$0
为执行的文件名$#
为传递到脚本的参数个数$*
为引用所有参数;用双引号时,” * “ 等价于 “1 2 3”(传递了一个参数)$@
为引用所有参数;用双引号时,“@” 等价于 “1” “2” “3”(传递了三个参数)
#!/bin/bash
echo "script_name: $0"
echo "para1: $1"
echo "para2: $2"
echo "para3: $3"
# bash test.sh {2..4}
# 条件语句
if 条件语句
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
写成一行
a=10; b=20; if [ $a == $b ]; then echo "a is equal to b"; fi
case 分支语句:可用到命令行解析中
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 循环
# do 可以另起一行,删除分号
for var in list; do
command
done
示例:
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
# 99 乘法表
for i in {1..9}; do
for j in $(seq $i); do
echo -n -e "$j*$i=$[j*i]\t"
done
echo
done
读取文件的每一行
cat file.txt | while read line; do
echo $line
done
# 整数条件
# 字符串条件
-n
- 可用于检测一个变量是否已经定义并且值不为空
[[ -z STR ]] # 空字符串 可检查环境变量是否被定义
[[ -n STR ]] # 非空字符串
[[ STR == STR ]] # 相等
[[ STR = STR ]] # 相等(同上)
[[ STR =~ STR ]] # 正则表达式
bc
:基础计算器(basic calculator)
文件条件
-f # 文件
-d # 目录
-e # 文件/目录是否存在
test 命令
原生 bash 不支持简单的数学运算,可通过 expr
命令(最常用)来实现
# 表达式和运算符之间要有空格
# 完整的表达式要被 ` ` 包含
val=`expr 2 + 2`
# 乘号(*)前边必须加反斜杠(\)才能实现乘法运算
val=`expr $a \* $b`
字符串切片 ${str:1:4}
# 删除变量;变量被删除后不能再次使用
unset name
# 获取字符串长度
echo ${#str}
echo ${#str[0]}
# 重定向
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 的标准输入
# 数据处理相关工具
参考资料
《命令行中数据科学》
100+ Command Line Tools for Data Visualization / Alex Garcia | Observable (opens new window)
对算术表达式的值进行引用时需要使用 []
或 (())
,两者作用相同
shell 脚本常用的环境变量
RANDOM
$RANDOM # 生成0~32767之间的随机数
$[RANDOM%num] # 生成0~num之间的随机数;对算术表达式的值进行引用时需要使用[]
shell,小数运算并取整
# 10/3 运算结果的整数部分
# -d "." 参数指定使用小数点作为分隔符,-f1 参数指定提取第一个字段,也就是整数部分
echo "scale=2; 10/3" | bc | cut -d "." -f1
sed 进行多次替换:用 ;
号或者 -e
参数
注意,使用分号将多个替换命令串联起来时,每个命令的末尾不能有空格,否则可能导致语法错误
# 两者等价
# 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 命令
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/ (opens new window)
sleep 3s
sleep 3
sleep m
sleep h
sleep d
# 其他
重复输出字符:How to repeat a character 'n' times in Bash - nixCraft (opens new window)
# 重复输出等号
printf '==%.0s' {1..20}; printf '\n'
# 定义函数
repeat(){
for i in {1..90}; do echo -n "$1"; done
}
repeat '-'; echo
repeat '='; echo