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"

shell进阶的更多相关文章

  1. 自学linux——12.shell进阶

    Shell进阶 当把在Windows中写好的脚本传到linux中使用时,在Windows下每一行结尾是\n\r,而Linux下则是\n,所以会多出来\r,在linux中运行脚本时,需执行: sed - ...

  2. shell进阶教程

    背景:就自己常用的shell脚本写作风格,总结了一些知识点.也是作为交接工作的一部分文档.部分内容单独写 #!/bin/sh # shell脚本进阶教程 # 1.常用知识点:变量设置/日期设置/格式化 ...

  3. Shell进阶精品课程

    课程链接 Shell精品进阶教程:理解Shell的方方面面 课程目标 系统性的掌握shell相关知识,进阶shell脚本能力,对shell各方面了然于心 适用人群 具备shell基础但想深入.系统性掌 ...

  4. [SHELL进阶] (转)最牛B的 Linux Shell 命令 (四)

    1.查看ASCII码表 man 7 ascii  很多人初学编程都会接触到ascii码的概念,有时候为了查某个符号的ascii值,可能还得翻箱倒柜找出当年的课本?Linux Manpage里面其实包含 ...

  5. [SHELL进阶] (转)最牛B的 Linux Shell 命令 (三)

    1. 更友好的显示当前挂载的文件系统 mount | column -t 这条命令适用于任何文件系统,column 用于把输出结果进行列表格式化操作,这里最主要的目的是让大家熟悉一下 columnt ...

  6. [SHELL进阶] (转)最牛B的 Linux Shell 命令 (二)

    1.用你最喜欢的编辑器来敲命令 command <CTRL-x CTRL-e> 在已经敲完的命令后按 <CTRL-x CTRL-e> ,会打开一个你指定的编辑器(比如vim,通 ...

  7. linux shell 进阶篇、shell脚本编程-创建函数

    使用函数 #!/bin/bash # testing the script function myfun { echo "This is an example of a function&q ...

  8. shell进阶函数

    函数的定义和用途 函数function是由若干条shell命令组成的语句块,实现shell代码的重用和模块化编程. 函数和shell程序的异同点 它与shell程序形式上是相似的,不同的是它不是一个单 ...

  9. [shell进阶]——shell多线程

    关于shell的多线程 1. 多线程并发执行任务,而不用一台台的串行执行,能更快更高效 2. Shell并没有多线程的概念,所以: * 一般使用wait.read等命令技巧性地模拟多线程实 * 使用命 ...

  10. shell 进阶之匹配字符串

      一,操作字符串 1,字符串长度 expr 命令取字符串函数 自带shell函数读取 2,匹配字符串开头字串的长度   !!!!!!!!!!!!$substring是正则表达式.!!!!!!!!! ...

随机推荐

  1. ES6函数参数默认值作用域的模拟原理实现与个人的一些推测

    一.函数参数默认值中模糊的独立作用域 我在ES6入门学习函数拓展这一篇博客中有记录,当函数的参数使用默认值时,参数会在初始化过程中产生一个独立的作用域,初始化完成作用域会消失:如果不使用参数默认值,不 ...

  2. C 语言实例 - 字符转 ASCII 码

    C 语言实例 - 字符转 ASCII 码 C 语言实例 C 语言实例 ASCII 定义了 个字符. 分类: 一:-.(删除键)是控制字符 二:空白字符:空格(). 制表符. 垂直制表符. 换行. 回车 ...

  3. tinymce 富文本简单使用

    tinymce.init({ //选择器 selector:'textarea', //配置顶部的菜单栏显示隐藏 menubar: false, //配置中文(默认没有中文包,需要到官网下载,放到la ...

  4. OSPF-1-OSPF的数据库交换(2)

    2.Hello过程: (1)在同一子网中发现其他运行OSPF的路由器 所有启用了OSPF的接口,都会监听发往224.0.0.5的组播Hello消息,这是表示所有OSPF路由器的组播地址.Hello包使 ...

  5. python 基础(四) 函数

    函数 一.什么是函数? 函数是可以实现一些特定功能的 小方法 或者是小程序 优点: 提高 了代码的后期维护 增加了代码的重复使用率 减少了代码量 提高了代码可读性 二.函数的定义 使用 def关键+函 ...

  6. D.出题人的手环

    链接:https://ac.nowcoder.com/acm/contest/358/D 题意: 出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数. 有一天,出题人和妹子分 ...

  7. javascript要点(上)

    立即执行函数 即Immediately Invoked Function Expression (IIFE),正如它的名字,就是创建函数的同时立即执行.它没有绑定任何事件,也无需等待任何异步操作: ( ...

  8. (AOP)理解

    AOP的全称: Aspact  Oriented  Programming AOP的目标(作用):让我们可以“专心做事”  日志记录,事务处理,异常捕获,缓存操作. AOP原理 将复杂的需求分解出不同 ...

  9. LINQ查询返回DataTable类型[轉]與将DataTable序列化为Json格式【轉】

    (原文地址:http://xuzhihong1987.blog.163.com/blog/static/26731587201101853740294/) LINQ查询返回DataTable类型 在使 ...

  10. MySQL主从复制原理介绍

    1)在mysql主库上,将改变记录到二进制日志(binary log)中. 2)在mysql从库上,IO线程将mysql主库上二进制日志(binary log)复制到中继日志(replay log)中 ...