Bash Scripting
简介
记录一下bash脚本编写的东东,可以参考cheatsheet
调试打印¶
在Bash脚本里打开打印,并利用shellprof 来./shellprof ./testcase.sh
计算时间。
#!/bin/bash
# 使用 trap 来捕获 DEBUG 信号,每次执行命令前触发
trap 'echo "$BASH_COMMAND"' DEBUG
# 设置调试模式打印前缀PS4,包含时间戳和行号
export PS4='+ $(date "+%Y-%m-%d %H:%M:%S.%3N")\011 '
set -x # 开启调试模式
基础知识¶
参数¶
$?
是上一个指令执行的状态值$@
代表shell脚本的命令行参数.$1
,$2
, etc., 分别代表命令行传入的第一个和第二个参数。举例,对于命令./run.sh XXX YYY
,$1
代表XXX
,$2
代表YYY
。
#
匹配并删除最短前缀
str="/path/to/foo.cpp"
echo "${str%.cpp}" # /path/to/foo
echo "${str%.cpp}.o" # /path/to/foo.o
echo "${str%/*}" # /path/to
echo "${str##*.}" # cpp (extension)
echo "${str##*/}" # foo.cpp (basepath)
echo "${str#*/}" # path/to/foo.cpp
echo "${str##*/}" # foo.cpp
在 Bash 脚本中,#
和 ##
符号用于字符串操作,具体用于删除前缀部分:
${str#pattern}
:删除变量str
中最短匹配pattern
的前缀。${str##pattern}
:删除变量str
中最长匹配pattern
的前缀。
例如:
echo "${str##*.}"
:这行代码使用##
删除了最后一个.
及其前面的所有内容,从而只保留了文件扩展名cpp
。这是因为*
匹配所有字符。echo "${str##*/}"
:这行代码使用##
删除了最后一个/
及其前面的所有内容,因此只保留了文件名foo.cpp
。${str#*/}
删除了第一个/
之前的部分,结果是path/to/foo.cpp
。${str##*/}
删除了最后一个/
之前的所有部分,结果是foo.cpp
。
这两个符号用于简化路径处理和提取文件名等。
变量作用域¶
- Bash 中的变量是 全局变量,也就是说,在脚本中的任何地方都可以访问到这个变量,除非使用 local 关键字将其作用域限制在特定的函数中。
local
声明的变量确实限制了它的作用域,但作用域仅限制在当前函数及其子函数(嵌套函数)内。对于嵌套函数,还是共用(读取和修改)上层的local变量。
函数传参¶
- Bash里的函数传参和脚本的命令行参数也是共用
$@
和$1
等,但是默认是函数的局部变量。 - 如果忘记使用局部变量,这常会导致一个问题:
- 外层的for循环的i被内层函数的for循环i修改导致循环异常。
- 解决方案:需要将内层函数的for循环i定义为local,来与上层的隔离。
其他¶
/dev/null
是一个几乎不管向它写入什么,都只返回成功,但是什么都没真的写入的文件。换句话说就是个“无底洞”,扔进去的东西肯定算扔进去了,但是扔进去就看不见了。
Environment¶
# read
SCRIPT_DIR="$(dirname $0)"
# set
export HOSTNAME="$(hostname)"
# check Environment
if [[ -z "${ITHEMAL_HOME}" ]]; then
echo "ITHEMAL_HOME environment variable must be set!"
exit 1
fi
实例¶
判断docker是否启动
尝试获取sudo权限
重连或者创建一个到名称为$1
的tmux
窗口
参考文献¶
无