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. ZROI #364. 【2018普转提day18专题】嘤嘤嘤

    ZROI #364. [2018普转提day18专题]嘤嘤嘤 直接贴代码 具体见注释 #include<stdio.h> #include<cstring> #include& ...

  2. HTML的基础结构

    <html>内容</html> 解释:HTML文档的文档标记,也称为HTML开始标记 功能:这对标记分别位于网页的最前端和最后端 <head>内容</head ...

  3. 101 Symmetric Tree 判断一颗二叉树是否是镜像二叉树

    给定一个二叉树,检查它是否是它自己的镜像(即,围绕它的中心对称).例如,这个二叉树 [1,2,2,3,4,4,3] 是对称的.    1   / \  2   2 / \ / \3  4 4  3但是 ...

  4. Java微信公众平台开发(九)--微信自定义菜单的创建实现

    自定义菜单这个功能在我们普通的编辑模式下是可以直接在后台编辑的,但是一旦我们进入开发模式之后我们的自定义菜单就需要自己用代码实现,所以对于刚开始接触的人来说可能存在一定的疑惑,这里我说下平时我们在开发 ...

  5. Mongo学习

    几种可能存在的实体类型 public class AAA{ public List<Common> CommonList{get;set;} } public class BBB{ pub ...

  6. AJPFX关于子类父类中的构造

    1.子父类中的构造函数不存在重写,因为子父类的构造函数名字不一样(重写要求子父类的方法名字一模一样,包括参数列表)2.子类创建对象时会先运行父类的构造函数再运行子类的构造函数.因为每个子类的构造函数的 ...

  7. js实现接口的几种方式

    Javascript模仿接口可以有三种方式:1.注释法 2.检查属性法 3.鸭式辨形法 1.注释法:此方法属于程序文档范畴,对接口的继承实现完全依靠程序员自觉 /* interface People{ ...

  8. Java编程基础-字符串

    在Java语言中,字符串数据实际上由String类所实现的.Java字符串类分为两类:一类是在程序中不会被改变长度的不变字符串:另一类是在程序中会被改变长度的可变字符串.Java环境为了存储和维护这两 ...

  9. 洛谷 P1048 采药

    采药 01背包模板题. #include <iostream> #include <cstdio> using namespace std; //Mystery_Sky //一 ...

  10. Wrapper class package.jaxws.methodName is not found. Have you run APT to generate them?解决方案

    使用JAX-WS 2.X基于Web容器发布WebService报错,错误信息类似于: Wrapper class package.jaxws.methodName is not found. Have ...