Linux shell 编程
shell脚本
$PATH环境变量
为什么我们可以在任何路径执行ls
命令了?
是因为环境变量$PATH
的帮助,当我们执行一个命令,系统会按照PATH的设置去每个PATH定义的目录下查询文件名为ls的可执行文件,如果多个目录有同名的文件,那么先查询到的先执行。
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
type命令
"" 和 ''区别
重定向
- 注意在 < > 左边的变量不会展开
#!/bin/bash ip=10.1.59.43 cmd="ping -c 2 ${ip} &> /dev/null" echo ${cmd} ${cmd} # 这里会报错,需要用 eval ${cmd}
eval
数据流重定向
- 标准输入,使用
<
- 标准输出,使用
>
- 标准错误输出,使用
2>
命令执行判断
-
cmd1;cmd2
sync; sync; shutdown -f
-
cmd1 && cmd2
- 若cmd1执行正确则执行cmd2
- 若cmd1执行错误则不执行cmd2
查看txt文件是否存在,存在就新建txt2。 ls txt && touch txt2
-
cmd1 || cmd2
- 若cmd1执行正确则不执行cmd2
- 若cmd1执行错误则执行cmd2
查看txt文件是否存在,不存在就新建txt。 ls txt || touch txt
-
cmd && cmd1 || cmd2
- cmd 执行成功则执行cmd1,执行失败则执行cmd2,实际上是 (cmd && cmd1) || cmd2
查看txt是否存在,存在输出exit,不存在输出no exit test -f txt && echo 'exit' || echo 'no exit'
shell变量
疑问:shell环境变量以及set,env,export的区别?
-
基础
name="admin" echo '$name' 输出:$name echo "$name" 输出:admin unset name 取消变量
-
环境变量
env 查看环境变量 set 查看所有变量(环境变量与自定义变量)
shell 脚本执行方式
-
sh shellscript.sh
和./shellscript.sh
都是在使用一个新的bash环境(子进程)来执行脚本内的内容。 -
source shellscript.sh
是在原父进程执行脚本内容。
shell 脚本默认变量
变量 | 意义 |
---|---|
$# | 指传给脚本的参数个数 |
$0 | 指脚本文件本身名字 |
$@ | 传给脚本的所有参数(不包括$0) |
$$ | 是脚本运行的当前进程ID号 |
$? | 显示最后一个命令的退出状态,0表示没有错误,其他表示有错误 |
语法
-
变量声明
declare -[aixr] variable -i 声明定义为整数类型 例子:declare -i sum=10+20 -r 将变量设置成readonly类型。不能修改,也不能重设 -a 将变量定位数组类型
-
local 变量
-
if else
if [ $1x == "ab"x ]; then echo "you had enter ab" elif [ $1x == "cd"x ]; then echo "you had enter cd" else echo "you had enter unexpected word" fi
- 与
if [ 表达式1 -a 表达式2 ]
- 或
if [ 表达式1 -o 表达式2 ]
- 与
-
case esac
case $变量名称 in "第一个变量内容") ...... ;; # 有2个分号 "第二个变量内容") ...... ;; # 有2个分号 ...... esac
-
for do done循环
// 固定循环 for var in con1 con2 con3 do ...... done // 数值处理 for i in `seq 1 2 100` do ...... done
-
while do done循环
while [条件判断式] do ...... done
-
until do done循环
until [条件判断式] do ...... done
数值运算
#! /bin/bash
service_port=10000
log_service_port=$(expr $(service_port) + 1)
shell 函数返回字符串
shell函数只能返回数字,不允许返回字符串,但是可以用点小技巧返回字符串。
#! /bin/bash
function return_str()
{
local l_str="hello world"
echo "${l_str}"
}
str=$(return_str)
echo ${str}
向函数传递数组和从函数返回数组
local
var="hello"
function test()
{
local var="world";
echo "${var}"
}
test // 输出 world
数组
shell中的数据分为2类:一类是普通数组,另一类是关联数组。
-
数组定义方式
array_test=(1 2 3 4) declare -a array_test # 先声明一个空的数组,后面可以根据索引来动态添加 echo ${!array_test1[*]} echo ${#array_test1[*]} # 显示数组中的元素个数(只统计值不为空的元素)
-
比较两个字符串是否相等的办法是:
if [ "$test"x = "test"x ]; then
这里的关键有几点:
1 使用单个等号
2 注意到等号两边各有一个空格:这是unix shell的要求
3 注意到 "$test"x 最后的x,这是特意安排的,因为当 $test 为空的时候,上面的表达式就变成了 x = testx,显然是不相等的。而如果没有这个x,表达式就会报错:[: =: unary operator expected
字符串替换
https://www.cnblogs.com/gaochsh/p/6901809.html
判断一个变量是否为空
#!/bin/bash
function check_var_is_null()
{
local l_var=$1
if [ ! -n "${l_var}" ]; then
echo "var is null"
else
echo "var is not null"
fi
}
para1=""
para2=
check_var_is_null ${para1}
check_var_is_null ${para2}
对文件和目录存不存在
#!/bin/bash
function file_is_exist()
{
local l_file=$1
if [ -f "${l_file}" ]; then
echo "found"
else
echo "not found"
fi
}
判断式 | 意义 |
---|---|
-e filename | 判断文件名是否存在 |
-f filename | 判断文件名是否存在且为文件 |
-d filename | 判断文件名是否存在且为目录 |
-b -c -S -p -L | 判断文件名是否存在且为块设备,字符设备,Socket文件,管道文件,连接文件 |
-r filename | 检测该文件名是否存在且具有读权限 |
-w filename | 检测该文件名是否存在且具有写权限 |
-x filename | 检测该文件名是否存在且具有执行权限 |
n1 -eq/ne/gt/ge/lt/le n2 | n1 相等/不等/大于/大于等于/小于/小于等于 n2 |
str1 = str2 | 字符串str1是否等于字符串str2 |
str1 != str2 | 字符串str1是否不等于str2 |
-z str | 判断字符串str是否为空串 |
-a | 2个条件同时成立 -r file -a test -x file |
-o | 任何一个条件成立 |
! | 反向 |
文本替换
#!/bin/bash
function global_replace() {
local l_file=$1
local l_old_word=$2
local l_new_word=$3
eval sed -i 's/${l_old_word}/${l_new_word}/g' ${l_file}
if [ $? -ne 0 ]; then
echo "error: replace word faild, exit"
exit 1
fi
}
函数传参注意
#!/bin/bash
function func_param()
{
local l_var=$1;
echo "${l_var}"
}
mysql_user_info="-usheng -psheng0"
func_param ${mysql_user_info} // 输出 -usheng
func_param "${mysql_user_info}" // 输出 -usheng -psheng0
推荐一个shell代码片段学习
https://github.com/dylanaraps/pure-bash-bible
编写可靠shell脚本技巧
-
-x
在执行每一个命令之前把经过的变量展开之后的命令打印出来。 -
-e
遇到一个命令失败(返回值非0)时,立即退出。
但是如果有时确实需要忽略个别的返回码。可以使用|| true
,如:[cmd] || true 或者 [cmd] || ret=$?
-
-u
试图使用未定义的变量,立即退出。#!/bin/bash set -u echo ${var} echo "here"
输出:./te.sh: line 4: var: unbound variable
-
-o pipefail
只要管道中的一个子命令失败,整个管道命令就失败。 -
timeout 限制运行时间
有时候,需要对命令设置一个超时时间,这时可以使用timeout
命令。timeout 600s [cmd] arg1 arg2
命令在超时时间内运行结束时,返回码为 0,否则会返回一个非零返回码。
shellcheck
shellcheck 是一款实用的 shell脚本静态检查工具。
项目地址:https://github.com/koalaman/shellcheck
ubuntu 安装
apt-get install shellcheck
多任务并行
#!/bin/bash
for i in {1..254};do
ip="192.168.80.$i"
ping -c 2 $ip &> /dev/null && echo $ip is up &
done
wait
参考资料