shell 中的高级用法

1.if

单重判断

if cmd; then
cmd
cmd
cmd
fi

多重判断

单分支

if  cmd;then
cmd
elif
cmd
fi

双分支

if cmd; then
cmd
elif cmd;then
cmd
elif cmd;then
cmd
else
cmd
fi

用于当判断条件的参数

逻辑判断

-a && 与

-o || 或

! 非

=~ 左边变量 ,右边扩展的正则表达式,不能写双引号

-z 判空

== 相等

!= 不相等

大小判断

-eq //等于

-ne //不等于

-gt //大于 (greater )

-lt //小于 (less)

-ge //大于等于

-le //小于等于

文件比较符

-e 判断对象是否存在

-d 判断对象是否存在,并且为目录

-f 判断对象是否存在,并且为常规文件

-L 判断对象是否存在,并且为符号链接

-h 判断对象是否存在,并且为软链接

-s 判断对象是否存在,并且长度不为0

-r 判断对象是否存在,并且可读

-w 判断对象是否存在,并且可写

-x 判断对象是否存在,并且可执行

-O 判断对象是否存在,并且属于当前用户

-G 判断对象是否存在,并且属于当前用户组

-nt 判断file1是否比file2新 [ ``"/data/file1" -nt ``"/data/file2" ]

-ot 判断file1是否比file2旧 [ ``"/data/file1" -ot ``"/data/file2" ]

2.case

要注意的是case 中使用的是引用变量,而不是声明变量名,$xxx

case支持glob风格的通配符:

*: 任意长度任意字符

?: 任意单个字符

[]:指定范围内的任意单个字符

a|b: a或b

case $num 变量引用 in
1|2|3) 判断条件 ,可以使用通配符
cmd1;
;; 根据;;来结束一个case段
4|5|6)
cmd2;
;;
*)
cmd3;
;;
esac

echo $passwd | passwd stdin user 设置用户密码

3.for

for 变量名(不是变量引用,不带$) in 列表;do

循环体

done

实例

for num in {1..10};do
echo num is $num;
done

列表生成方式:

  1. 直接给出列表
  2. 整数列表:

    (a) {start..end}

    (b) $(seq [start [step]] end)
  3. 返回列表的命令

    $(COMMAND)
  4. 使用glob,如:*.sh
  5. 变量引用;$@, $*

列表可以用任意的合集,用命令解析得到的合集也可以,比如填 ls /bin,支持通配符

{1..100..3} 1到100,每次步进3

unset sum 删除变量sum,防止影响

for中使用多行重定向的话 。需要把第一个EOF加- 或者把EOF结尾标志顶格。否则无法识别

for i in {1..10};do
cat >>f1<<-EOF
ASDASD
ASDASD
EOF
done

或者

for i in {1..10};do
cat >>f1 <<EOF
ASDASD
ASDASD
EOF
done

4.for循环的第二种格式语法

sum=0

for ((i=1;i<=100;i++))

let sum+=i

done

for i in {1..3};do

for j in {1..10};do

if [ \(j -eq 5 ];then continue 2;fi
echo j=\)j

done

done

这边就表示,当j等于5的时候,跳出第二层循环 。不是j循环的第二次,而是第二层!!!就是跳出i循环的当次循环,直接执行i的下次循环

5.参数移除

shift n

shift[n] 参数左移,n可以指定具体数字,表示每次抛弃的参数个数

比如 1 2 3

就会先处理完1,然后把1抛弃,处理2,以此类推

6.并行执行

并行执行 把所有语句用 {} 包裹,最后加上 & 就是把语句放在后台并行执行。

wait 脚本执行完成后自动退出,不需要用户按回车

为什么会输出两次192.168.30.1

let命令特性点:如果他操作的变量值为 0 返回的是假,

如果变量非0,返回是真

比如 i=0

leti++ ,那么这一次返回的是0

unset i

let i++

echo $? 为 假 1

unset i

let ++i

echo $? 为真 0

n=10;seq 1 \(n 这样用这个,
n=10;echo {1..\)n} 这样是会报错的,不能这样执行

n=10;eval echo {1..$n} eval 会扫描并替换变量,然后执行该语句

用花括号分割变量

比如 \(ix\)j ,可能后面的\(j会识别成x\)j

写成

\(ix\){j} 即可

openssl rand -base64 20 | tr -dc '[: alpha :]'|head -c8

$[ 这样的格式里面可以做运算操作 ]

while 条件;do

循环体

done

: 返回真 等同于 true

selinux

用pgrep 查看进程是否存在,然后监控

pgrep 可以匹配到返回是true(0),而匹配不到会返回false(1)

向进程发送0信号,可以检测进程是否存在,因为0 信号不会对进程进行任何处理,但是会检查错误。

until 条件;do

循环体

done

与while相反,条件为假时进入循环,条件为真时,退出

who |grep USERNAME 查看该用户是否登录

7.while

while cmd;do

cmd

if cmd;then

continue 跳过当次执行

fi

done

while cmd;do

cmd

if cmd;then

break 退出当前循环块

fi

done

continue 和 break 后面可以跟数字,用于结束第N层的循环。

最里面的循环是第一层,往外层递增

whlie read line;do

循环体

done

while循环的特殊用法(遍历文件的每一行):

while read line; do

循环体

done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line

df | while read line;do

处理df的每一行,支持管道

done

8.until 循环

until cmd;do
循环体
done

进入条件:cmd为假

退出条件:cmd为真

本质就是一个跟while相反的条件判断

9.select 创建菜单

PS3="Please choose the menu 1-4 : " 修改运行脚本时候的select提示符

select variable in list

do

循环体命令

done

$REPLAY存储用户手动输入的内容

自动将List转换为菜单,根据选择的项,给变量赋值

PS1命令行提示符

PS2多行重定向提示符

PS3 select 命令提示符

select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 退出循环

select 经常和 case 联合使用

与 for 循环类似,可以省略 in list,此时使用位置参量

下面是一个简单的示例:

#!/bin/bash
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
break;
done
echo "You have selected $var"
</pre>

该脚本的运行结果如下:

What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux</pre>

10.trap 捕获信号

trap 'echo press ctrl+c' int 捕获Int信号 ,转换为echo press ctrl +c

trap '' # 捕获信号,并且什么都不做,相当于拦截信号

trap '-' # 使信号恢复,恢复原信号的操作

可以捕捉15信号,使程序不可以正常关闭。但是无法捕捉9这个强制关闭的信号

脚本任务

alias.sh 配置别名

vim.sh 配置vim

yum.sh 配置yum

pack.sh 安装软件包

declare -f func4 查询是否存在func4函数

如果要在脚本里执行rm相关操作,需要检查对应的路径是否正确,变量是否赋值成功

11.函数

定义格式

语法一:

f_name ()
{
...函数体...
}

语法二:

function f_name
{
...函数体...
}

语法三:

function f_name ()
{
...函数体...
}

函数的优先级比别名高

函数的生效范围是当前shell

local 改变变量的有效范围,让他只在该函数内有效

全局变量 > 普通变量 > local 变量

declare 声明的变量,也是local 类型的

declare -ig num=100 加g之后定义,变量就变成了普通变量,不再是local变量

return 退出函数本身

在函数中使用echo 输出变量 ,就可以把输出写在if中直接判断

version (){ echo 1 }

if [ version -eq 1 ] 判断是成立的

add() { echo $[$1+$2] }

add 1 2

输出3

函数复用

把函数保存为bash脚本,

新的脚本中使用

source functions (脚本名),相当于引用该脚本

之后就可以使用该脚本中的函数

action "commadn successful " 可以显示成功

action "xxx" /bin/false 表示失败

action "xxx /bin/true 表示成功

/etc/init.d/functions 储存了系统内置的函数

函数可以覆盖定义

export -f func1 将函数声明为全局函数,让子shell也可以使用该函数,定义函数的时候,不可以使用export

函数递归调用的时候,只有递归结束的时候,才会执行递归后的操作。

数组

关联索引 把数组的索引设置为自定义的格式,而不仅仅是数字

bash的数组支持稀疏索引(索引不连续),比如0,1, 3 有东西,2 没有 那么数组长度是3 ,但是他们不是连接的。输出2的话是空

declare -a ARRAY_NAME 普通数组

declare -A ARRAY_NAME 关联数组 必须先声明再使用

${a[1]}

echo ${name[* ]}

echo ${name[@]}

都代表输出数组中的所有元素

number=({1..10}) 这样也可以定义数组,()中存放任意生成多个字符串的命令都可以。通配符,正则表达式查找,bash命令,都能放

read -a title a b c 定义数组title ,内容是a b c

echo a b c | read -a s 定义数组s,内容是a b c (这样是错误的!!管理是不支持交互式赋值的)

关联数组一定要先定义再使用,否则数组变量会出问题

关联数组更像一个字典

${#name[* ]} 显示name数组的数组长度

因为使用了管道,所以开启了子shell,导致变量没有值

这样的话,在循环中使用的数组,声明周期单独只在循环中生效,因为这个时候while read line 使用的是开启的子shell

字符串处理

${var#*word}

str没有配置 表示变量不存在,没有声明

生成随机文件名

mktemp /data/tmpXXXXX 表示有五位的随机字符

expect

自动处理交互式命令,需要安装yum 包

自动传输文件

!/usr/bin/expect

spawn scp /etc/fstab 192.168.8.100:/app

expect {

"yes/no" { send "yes\n";exp_continue }

"password" { send “magedu\n" }

}

expect eof

spawn 表示捕获该命令 ,通过expect 来提交信息。当复制命令遇到yes或者no,就自动提交yes,然后继续执行。

当遇到password ,提交magedu

/etc/ssh/sshd_config

GSSAPIAuthentication no 关闭代理 79行

USEDNS NO 启动 115行

修改完成后 执行 systemctl sshd restart 重启sshd服务

加速sshd访问速度

自动登录

!/usr/bin/expect

spawn ssh 192.168.8.100

expect {

"yes/no" { send "yes\n";exp_continue }

"password" { send “magedu\n" }

}

interact

expect eof

interact 表示开启交互式

expect eof 结束expect 捕获

interact 搭配 #expect eof 表示登录终端后,释放对ssh的控制,这样expect就不会再继续捕获命令

expect 写一个控制脚本

用bash调用该脚本,做批量机器处理

矩阵转换

vim matrix.sh
#!/bin/bash arr=([00]=1 [01]=2 [02]=3 [10]=4 [11]=5 [12]=6 [20]=7 [21]=8 [22]=9)
size=3 showmatrix () {
for ((i=0;i<size;i++));do
for ((j=0;j<size;j++));do
echo -e "${arr[$i$j]} \c"
done
echo
done
} echo "Before convert" showmatrix for ((i=0;i<size;i++));do
for ((j=i;j<size;j++));do
if [ $i -ne $j ];then
temp=${arr[$i$j]}
arr[$i$j]=${arr[$j$i]}
arr[$j$i]=$temp
fi
done
done echo "After convert"

最新文章

  1. TextWatcher 编辑框监听器
  2. [外挂6]在指定位置下棋 SendMessage函数
  3. HDU 4738 Caocao&#39;s Bridges(Tarjan求桥+重边判断)
  4. flock防止重复rsync
  5. PHP Array 函数
  6. Codeforces Round #367 (Div. 2) Hard problem
  7. Silverlight DataGrid标题行居中
  8. C# 4 dynamic 动态对象 动态类型转换
  9. UVALive 6959 - Judging Troubles
  10. Android 自定义shape圆形按钮
  11. SQL语句流程函数
  12. Python—课时ONE
  13. 【RL-TCPnet网络教程】第31章 Telnet远程登录基础知识
  14. JS控制开灯关灯
  15. GNU C 与 ANSI C(下)
  16. RxJS--Subject
  17. 【Git】一、Git简介
  18. java版云笔记(四)
  19. xftp Initialize Flexnet Service failed / Error code: 50003
  20. 【bzoj2699】更新 dp

热门文章

  1. STP-5-STP配置及分析
  2. FMDB存储模型对象(以二进制存储)用NSKeyedArchiver archivedDataWithRootObject序列号,NSKeyedUnarchiver unarchiveObjectWithData反序列化(重点坑是sql语句@&quot;insert into t_newsWithChannel (nwesName,newsType) values (?,?)&quot;)一定要用占位符
  3. 在 Linux 环境直接复移动硬盘上的 GRUB
  4. getpass不起作用
  5. (wp8.1开发)添加数据(SQLite)库到app
  6. Magento 0元订单 支付方式 -- Magento 0 Subtotal Payment Method
  7. Java基础之面向对象
  8. 6.html图像标记img
  9. {ubuntu}不能挂载windows
  10. tomcat 发布本地文件