基础
适用情况
- 自动化
- 开机即用
- 开发快
- 固化下可以节省重复操作
- 构建个人高效工作环境
不适用情况 - 需要具体操作
- 需要效率
- 需要保护源码
不使用C等语言的思路编写Shell,尽可能发挥整合其他工具效能,而非考虑用shell自身实现
执行
#!/bin/bash -x 开启调试模式
set -x 开启调试
set +x 关闭调试
在执行前后加入后ctrl+z切换到前台,然后再执行就有日志了
fg切回后台
常用Linux命令
find
find [path] [expression]
参数
-name 按文件名查找,支持和?
-iname 忽略大小写
-type 文件类型[f 普通文件;d 目录;l 符号链接]
-size 文件大小
-maxdepth,mindepth 递归深度
-username 用户所属
实例
find . -iname ".sh" 当前目录中地柜查找以.sh结尾的文件或目录
find . -maxdepth 2 -mindepth 2 -name “a” 在特定目录层级下查找
find . -name=“asdf” -exec ls -l {} ; 找到后针对文件执行命令,文件名带空格时更安全
find . ‘(’ -iname “a” -o -ipath “var” ‘)’ -a ! -size +5M 条件组合。
()组合表达式
-o 表示或
-ipath 路径包含“var”的文件
-a 与
! -size +5M 排除文件大小超过5M的文件
find . -iregex ‘.*’ 正则表达式
grep
参数
-r 递归查找
-n 显示行号
-i 忽略大小写
-v 反向查找
-E 正则查找
grep -ir ‘^x.*aaa’ .当前目录下递归查找,忽略大小写
grep ‘<c…h>’ /usr/share/dict/words 查找以c开头h结尾的五个单词
grep --‘-r’ 查找-r。转义
grep -E ‘(H|h)ello’ # 查找 ‘hello’ 或 ‘Hello’
-A10 -B10 -C10 # 显示下10行、上10行、上下10行
awk
awk ‘{print $3}’
awk -f awk_script_file input_files
sed
sed “s/3/three/g” filex
sed “/^1/s/3/three/g” filex
sed “/^1/s/3/three/gp” filex
sed -n “/^1/s/3/three/gp” filex
Shell
变量
#变量定义
FILENAME="ABC" # 等号左右不可加空格
#变量使用
echo $FILENAME
echo ${FILENAME} #花括号可选
echo "I have a txt file named ${FILENAME}.txt #但最好写上因为可以帮助编译器识别变量区间
readonly NAME #只读变量
local FILE #局部变量
unset FILE #删除变量
字符串
str='string'
str1="string"
字符串分为单引号和双引号
单引号
- 强引用,任何字符都是原样输出
- 不可转义
- 单引号内不能有单独的单引号(包括转义符),但可以成对出现用于字符串拼接
双引号
弱引用,可以加入转义和变量
NAME="bob"
echo "hello "$NAME"" # hello bob
echo "hello $NAME" #hello bob
echo 'hello '$NAME'' #hello bob
echo 'hello $NAME' #hello $NAME
#-------------------------------------
echo ${#NAME} #输出长度
echo ${NAME:1:4} #输出第2个到第4个字符
POS=1
LEN=3
echo ${NAME:$POS:$LEN} 输出1-3
echo ${NAME[@]} #输出字符串
string="He is a boy"
echo `expr index "$string" io` #查找字符i和o的位置(先出现哪个就计算哪个)
字符串替换
STRING="to be or not to be"
echo ${STRING[@]/be/eat} #to eat or not to be 替换第一个匹配项
echo ${STRING[@]//be/eat} #to eat or not to eat 替换所有出现的子字符串
echo ${STRING[@]// not/} #删除not
echo ${STRING[@]/#to be/eat now} #替换子字符串如果to be在开头的话
echo ${STRING[@]/%to be /eat now} #替换子字符串如果在末尾的话
echo ${STRING[@]/#to be/to be on $(date +%Y-%m-%d)} #使用shell命令输出替换
数组
array_name=(value0 value1 value2) #定义
declare -A site={["google"]="www.google.com"} #设置一个关联数组
a=${array_name[n]} #取数
echo ${array_name[@]} #取全部的数
length=${#array_name[@]} #取数组元素的个数
lengthnn=${#array_name[n]} #取单个元素的长度
基本计算
A=3
B=$((100*$A+5))
$0,$1 接收参数
$# 参数个数
$$ 脚本PID
$! 后台运行的最后一个进程的ID号
$? 运行状态
$* 以单字符串显示所有向脚本传递的参数
$@ 与上面的相同,不过使用时加引号,在引号中返回每个参数
if和关系运算符
-eq 相等
-ne 不相等
-gt 左边是否大于右边
-lt 左边是否小于右边
-ge 左边是否大于等于右边
-le 左边是否小于等于右边
布尔运算符
! 非
-o 或
-a 与
-z 判断字符串长度是否=0 if[ -z $a]
-n 长度是否不为0 if [-n "$a"]
$ 是否不为空
test运算符
if test $[num1] -eq $[num2] then #判断式
result=$[a+b] 计算a和b的值
逻辑判断
if test $[num1] -eq $[num2]
then
echo "equal"
else
echo "not equal"
fi
for val in item1 item2 ... itemN
do
something
done
while (($int<=5))
do
command
done
无限循环:
while :
do
done
while true
do
done
函数
不带任何参数
demoFun(){
echo "shell function!"
}
demoFun()
如果没有return,那么就会返回最后一条命令的返回值。return的取值范围为0-255
返回值通过$?获得
函数参数通过$n获得
funWithParam(){
echo "First param $1"
echo "second param $2"
echo "10th param ${10}"
echo "参数总共有 $# 个"
echo "输出所有参数: $*"
}
重定向
command > file 输出重定向到file
command < file 输入重定向到file
command >> file 追加重定向到file
n > file 文件描述符为n的文件重定向到file
n >> file 追加重定向
n >& m 输出文件m和n合并
n <& m 输入文件m和n合并
<< tag 将开始标记tag和结束标记tag之间的内容作为输入
# 0 stdin 1 stdout 2 stderr
# 2> 标准错误重定向
# & : 放到后台执行
实例
stdout和stderr合并后重定向到file
2>&1表示标准错误重定向到了和标准输出一样的地方
command > file 2>&1
command &> log.txt
command将stdin重定向到file1,stdout重定向到file2
command < file1 > file2
wc -l < readme.md # 统计readme.md行数
while read str; do
echo $str
done < readme.txt #代码块重定向,将readme.txt的内容放到标准输入之中
wc -l <<END 查看用户输入的行数,一直到遇到END之后才结束读取
shell的一些注意事项和实例
通配符
*
- -匹配0或多个任意字符 ?
- -匹配任意单个字符 []
- -匹配[]范围内任意单个字符
var="aa_bb_cc_dd"
echo "${var#*_}" # #表示删除匹配到的部分,*_表示通配符匹配。这里采用的是最短匹配
法.out:bb_cc_dd
echo "${var##*_}" # 最长匹配法 out:dd
echo "${var%_*}" #aa_bb_cc 删除最后一个_*及其右边的串
echo "${}var%%_*}" #删掉第一个及其右边的床 out:aa
** ? 的影响 ∗ ∗ 第一个语句, e c h o 中的 ?的影响** 第一个语句,echo中的 ?的影响∗∗第一个语句,echo中的?实际上是local a这个命令的返回值。
因此应按照第二个的方法写
对比[] [[]] (()) ()
[] 兼容性最好,是一个可执行程序
*
[[]] 比 [] 功能更多,更方便,更安全,但非Posix标准
*
(()) C风格的数值计算,例如((i++)) ((a + b * c))
*
() 用于创建执行子Bash进行
IFS
内部域分隔符
Shell环境变量分为两种,set为当前shell的内部域环境变量,env为全局环境变量。IFS作为一种set
变量,可以再命令替换和参数替换时根据IFS值来拆解读入的变量。
判断变量作用域:
env | grep IFS # 为空,说明为局部变量
set | grep IFS # 非空
a=${1:-"false}
如果1存在并且不为空那么a =1,否则就是a=false