写点什么

Bash 实用技巧

用户头像
麦迪文
关注
发布于: 2020 年 08 月 20 日
Bash 实用技巧

一、空值判断与设定默认值



常见做法:



if [[ "$SOME_VAR" == '' ]]; then
SOME_VAR=DEFAULT_VALUE
fi



比较简便的做法:



SOME_VAR=${SOME_VAR:-DEFAULT_VALUE}



如果你习惯副作用,还可以简化为:



${SOME_VAR:=DEFAULT_VALUE}



一个完整的例子:



#!/bin/bash
name=${1:-unknown}
echo "your name is $name"



二、空值判断与程序中断



常见做法:



if [[ "$SOME_VAR" == '' ]]; then
echo ERROR_MESSAGE
exit 1
fi



比较简便的做法:



${SOME_VAR:?ERROR_MESSAGE}



一个完整的例子:



#!/bin/bash
name=${1:?'require name'}
echo "your name is $name"



三、忘记 sudo



常见场景:



npm install -g vue
# npm WARN checkPermissions Missing write access to /opt/nodejs/lib/node_modules
sudo npm install -g vue



比较简便的做法:



npm install -g vue
# permission denied
sudo !! # 等价于 sudo npm install -g vue



!! 是重新执行上一条命令,sudo !! 则是使用 sudo 模式重新执行上一条命令。



一个完整的例子:



cat /etc/sudoers
# cat: /etc/sudoers: 权限不够
sudo !!



如果在 Vim 编辑保存时,忘记 sudo,则运行如下命令:



:w !sudo tee %



% 代表当前文件名, tee 命令用来复制当前输入到指定文件中。



一个具体的例子:



cd /etc/ssh/ssh_config.d
vim foo
# 编辑一些文本
# 尝试使用 ":wq" ":wq!"
# 尝试使用 ":w !sudo tee %"
# 使用 "q!" 退出
# 再次打开文件,检查更改是否生效
vim foo



四、设置调试选项



1、在每个命令被执行前先打印,在脚本中可以添加如下命令:



set -x



等价命令,可以在脚本外部使用如下命令运行:



bash -x SOME_SCRIPT_FILE



如果想关闭该选项,则把 - 改为 + (其他调试选项也是相同的做法),如下示例:



set +x



一个完整的例子:



#!/bin/bash
set -x
echo 'hello world'



2、试图使用未定义的变量,就立即退出,在脚本中可以添加如下命令:



set -u



这样做的好处是可以避免使用未定义变量造成非预期的结果,例如:



rm -rf "$SOME_DIR/data" # 等同于 rm -rf "/data"



但有时候在已经设置了-u 后,某些地方还是希望能把未定义变量展开为空串,可以这样写:



${SOME_VAR:-}



一个完整的例子:



#!/bin/bash
set -u
echo "your name is $name"
echo 'bye'



五、计算运行时间



time COMMAND



一个完整的例子(计算 1000 位小数的 PI):



time echo "scale=1000; 4*a(1)" | bc -l -q



六、使用 tee 将输出落盘



有时候我们会用到把好多条命令用管道串在一起的情况。如 cmd1 | cmd2 | cmd3 | ... 这样会让问题变得难以排查,因为中间数据我们都看不到。



这时可以用 tee 命令:



cmd1 | tee out1.dat | cmd2 | tee out2.dat | cmd3 > out3.dat



tee 命令的作用在于把输入流写入指定文件的同时,同时还保持原样输出到下一管道的输入流中,可以说该操作是透明的。



一个完整的例子:



ls -l | tee out.log
cat out.log



七、tail 查看日志



tail FILENAME



如果我们想打印末尾 N 行,则使用 -n N 选项,如果想实时查看日志输出,则添加 -f 选项。



一个完整的例子:



cat /etc/passwd | tail -n 1



八、检测命令运行状态



常见做法:



if ! SOME_COMMAND; then
exit $?
fi



比较简便的做法:



SOME_COMMAND || exit $?



一个完整的例子:



#!/bin/bash
foo() {
return 1
}
foo || exit $?

echo 'bye'



九、搜索字符串并显示上下文



命令如下:



grep PATTERN -A N -B N



PATTERN 是要搜索的模式字符串, -A N 向上返回指定行数, -B N 向下返回指定行数。



一个完整的例子:



man ls | grep -A 1 -B 1 -- -l



十、添加可读注释



文件头部示例:



#!/bin/bash
#
# This is a file header example.



函数示例:



#######################################
# Cleanup files from the backup directory.
# Globals:
# BACKUP_DIR
# ORACLE_SID
#######################################
function cleanup() {
# some command
}
#######################################
# Get configuration directory.
# Globals:
# SOMEDIR
# Outputs:
# Writes location to stdout
#######################################
function get_dir() {
echo "${SOMEDIR}"
}
#######################################
# Delete a file in a sophisticated manner.
# Arguments:
# File to delete, a path.
# Returns:
# 0 if thing was deleted, non-zero on error.
#######################################
function del_thing() {
rm "$1"
}



十一、长脚本使用 main()



如果脚本长到至少包含一个其它函数,这时就可以考虑添加 main 函数了。main 函数调用示例如下:



main "$@"



注意:这里使用 "$@" 而不是 "$*",原因是我们需要界定命令传递进来的不同选项和参数,而不是作为一个整体。



一个完整的例子(加减法计算器):



#!/bin/bash
#
# Calculator
#############################################
# Add
# Arguments:
# First number.
# Seconde number.
#############################################
function add() {
echo $((( n1 + n2 )))
}
#############################################
# Sub
# Arguments:
# First number.
# Seconde number.
#############################################
function sub() {
echo $((( n1 - n2 )))
}
#############################################
# Main
# Arguments:
# Calculate action, such as 'add' or 'sub'.
# First number.
# Seconde number.
#############################################
function main() {
local action=${1:?require action, such as add or sub}
local n1=${2:?require first number}
local n2=${3:?require second number}
case $action in
'add')
echo "$(add $n1 $n2)"
;;
'sub')
echo "$(sub $n1 $n2)"
;;
*)
echo "not support action."
;;
esac
}
main "$@"



十二、命令行启用 VI-STYLE



set -o vi



每次回车之后默认是在 Insert 模式下,按 ESC 之后,就回到 Command 模式了。



一个完整的例子:



# 错误输入 "pad" 命令,然后更正为 "pwd"



十三、快速备份



cp FILE_PATH{,.bak}



一个完整的例子:



>foo
cp foo{,.bak}



发布于: 2020 年 08 月 20 日阅读数: 58
用户头像

麦迪文

关注

道法自然 2018.01.13 加入

Go 语言从业者,崇尚领域驱动开发

评论

发布
暂无评论
Bash 实用技巧