Shell编程基础
变量
脚本开头使用#!/bin/bash指定要使用的shell,shell会通过PATH环境变量来查找脚本中使用的命令,可以使用echo $PATH来看下脚本会在哪些目录下查找命令,如果脚本中执行的命令没有在PATH环境变量中,也可以通过绝对或相对路径来引用. 在脚本中可以使用shell维护的环境变量也可以定义和使用自己的用户变量. 赋值等号两边不能存在空格
-
环境变量: 可以使用set命令查看当前环境变量列表,例如$HOME、$HOSTNAME、$USER等;
-
用户变量: 由字母数字下划线组成,长度不超过二十,区分大小写,变量、等号、值之间不能有空格,在shell脚本结束时会被删除掉,使用美元符号引用,例如name=“test”。使用用户变量保存命令执行结果:testing=$(date)
-
特殊参数变量
参数 描述 $ 0 $1 $2 入参 $# 参数个数 $* 入参列表,将所有参数当作单个参数 $@ 入参列表,单独处理每个参
重定向输入输出
- 输出重定向: > 追加:»
- 输入重定向: <
- 在脚本中使用< > 需要进行转义< >
- 内联输入重定向:
command << marker
content
marker
# 例如:
wc -l <<EOF
echo "aaa"
echo "BBB"
EOF
内联重定向到文件
cat >> demo.txt <<EOF
some content
EOF
文件描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
- &> 符号会将所有输出重定向到一个文件内
- exec 1>testout 在脚本中将STDOUT永久重定向到testout
- exec 3>./testfile 创建写描述符3
- exec 3>&- 关闭文件描述符3
- cat /dev/null > file.log 可快速清空日志
脚本中执行数学运算
- 使用美元符和方括号,只支持整型计算
- var1=$[1 + 5]
- var2=$[$var1 * 2]
- var3=$[2 / 3]
- 通过bc进行浮点型计算:
var1=$(echo "scale=4; 3.44 / 5" | bc)
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(bc<<EOF
scale = 4
a1=($var1 * $var2)
b1=($var3 * $var4)
a1+b1
EOF
)
echo "$var5"
退出脚本
默认情况shell会以脚本最后一个命令的退出状态码退出(0-255)
可以使用exit命令指定脚本的退出码,并通过echo $?查看程序是否执行成功
结构化命令
if语句
根据命令执行是否成功走不同分支
if command1; then
comands
elif comand2; then
comands
else
comands
fi
或者使用条件测试的方式
if [ condition ];then
comands
fi
条件测试
-
数值比较
比较 描述 n1 -eq n2 检查相等 n1 -ge n2 检查n1是否大于或等于n2 n1 -gt n2 检查n1是否大于n2 n1 -le n2 检查n1是否小于或等于n2 n1 -lt n2 检查n1是否小于n2 n1 -ne n2 检查n1是否不等于n2 -
字符串比较
比较 描述 str1 = str2 是否相同 str1 != str2 是否不同 str1 < str2 str1是否比str2大 str1 > str2 str1是否比str2小 -n str1 检查str1的长度是否非0 -z str1 检查str1的长度是否为0 -
文件比较
比较 描述 -d file file是否存在并是目录 -e file file是否存在 -f file file是否存在并是文件 -r file 是否存在并可读 -s file 是否存在并非空 -w file 是否存在并可写 -x file 是否存在并可执行 -O file 是否存在并属于当前用户所有 -G file 是否存在并默认组与当前用户相同 file1 -nt file2 file1是否比file2新 file1 -ot file2 file1是否比file2旧 -
复合条件测试
[ conditon1 ] && [ condition2 ] [ conditon1 ] || [ condition2 ]
- 使用双括号进行数学运算判断
(( expression )),支持的运算符号除普通运算符外还包括如下,大于小于符号不用转义 .
val++ 、val–、 ++val、 –val :自增自减
! :求反 ~:位求反 **:幂运算 «:左位移 »:右位移 &:位布尔和|:位布尔或 &&:逻辑和 ||:逻辑或
可以在if语句中使用双括号命令,也可以在脚本中的普通命令里使用来赋值
- 使用双方括号进行字符串比较
[[ express ]] bash shell支持模式匹配: if [[ $USER == r* ]]
case语句
case variable in
pattern1 | pattern2) commands1;;
pattern3) comands2;;
*) default commands;;
esac
for语句
for var in list
do
commands:$var
done
有时候使用for line in $(cat $file)读取文本文件,默认会以空格分隔而不是换行符,需要修改IFS. IFS值:内部字段分隔符
IFS.OLD=$IFS
IFS=$’\n’
#<在代码中使用新的IFS值>
IFS=$IFS.OLD
C语言风格for语句
for (( i=1; i <=10; i++ ))
do
...
done
while语句
while [ condition ]
do
other commands
done
break: 跳出内部循环
continue: 跳过本次循环
break n: 可跳出外部循环
continue n : 继续循环层级n的循环
处理用户输入
利用getopts处理用户输入参数
while getopts :ab:c opt
do
case "$opt" in
a) echo "found -a option" ;;
b) echo "found -b option ,with value $OPTARG" ;;
c) echo "found -c option" ;;
*) echo "Unknown option: $opt" ;;
esac
done
shift $[ $OPTIND - 1 ]
count=1
for param in "$@"
do
echo "Parameter $count: $param"
count=$[ $count + 1]
done
获取用户输入
if read -t 10 -p "Please enter your name: " name
then
echo "ok: $name"
else
echo "too slow"
exit 1
fi
使用临时文件
tempfile=$(mktemp tmp.XXXXXX)
exec 3>$tempfile
echo “test” >&3
exec 3>&-
rm -f $tempfile 2>/dev/null
mktemp -t 生成在/tmp/目录下,返回全路径
控制脚本
-
记录消息 date | tee -a testfile
-
trap捕获处理信号
trap commands signals
trap “echo ‘ sorry i have trapped Ctrl-C’” SIGINT
trap – SIGINT 删除捕获
- 后台作业相关
- command &:后台运行
- nohup comand: 后台运行
- jobs: 列举作业
- bg: 后台重启作业
- fg: 将后台作业调到前台继续执行,可指定job号
- nice renice: 调整作业优先级
- at: 定时执行作业
- atq: 定时作业队列
- atrm: 删除作业
- crontab定时任务时间表:
- min hour dayofmonth month dayofweek command
- anacron:开机执行错过作业
shell函数
- 函数名必须唯一,否则会有问题
function name{
commands
}
[[或者]]
name() {
commands
}
-
return 可以返回函数值:必须函数一结束就取$?;退出的状态码必须是0-255
-
超出255值可以使用 result=$(func1) 方式
-
每个函数可以单独使用自己的$# $1 $2 环境参数
-
变量作用域:
-
全局变量:不管在函数内外定义,脚本所有位置都可访问
-
局部变量:必须用local关键字显式声明
local temp=$[ $value + 5]
数组相关: 函数参数是数组情况处理:
function testit {
local newarray
newarray=('echo "$@"')
echo “The new array value is: ${newarray[*]}”
}
myarray=(1 2 3 4 5)
testit ${myarray[*]}
多进程执行函数
function multi {}
multi argu1&
multi argu2&
multi argu3&
wait
trap捕获信号
Trapping ctrl-c in Bash
You can use the trap builtin to handle a user pressing ctrl-c during the execution of a Bash script. e.g. if you need to perform some cleanup functions.
#!/bin/bash
[[trap]] ctrl-c and call ctrl_c()
trap ctrl_c INT
function ctrl_c() {
echo "** Trapped CTRL-C"
}
for i in `seq 1 5`; do
sleep 1
echo -n "."
done
debug
- 在调用脚本的时候开启deubg sh -x shell.sh
- 在脚本文件首行开启deubg #!/bin/bash -x
- 使用set开启deubg set -x
- -v 显示脚本所有行,详细模式,在脚本嵌套调用时比较有用 sh -v shell.sh
- -n 检查脚本的语法,不执行脚本的命令 sh -n shell.sh
远程执行命令
ssh -n ‘command’ 可避免在while循环中吞stdin数据