写这篇文章的目的很简单,由于爱并恨过;php
前段时间要改个安卓产品的脚本,惊奇发现理论是用shell,虽然实现的功能不复杂,但若是对没了解过shell或懂皮毛的同窗,改起来是至关痛苦(如jb),调试半天各类找文档,性价比过低了,巴不得用Python重构。。 html
虽然仍是能完成想要的结果,但花费的时间远超一开始想的,目前shell给jb的感受就如去年正则带来的噩梦通常,知道这玩意,会一丢丢,可是真正撸码改内容的时候,查半天文档,调试半天不如愿;java
所以就有了该篇,对新同窗而言,目的是让你快速了解shell,对于老同窗而言,目的是提供经常使用的shell命令快速唤醒记忆,而且贴出例子来快速实验,大神请右上,谢谢~node
此处手动@敏爷,由于敏爷也咨询了个shell的问题,建议都看看,巩固下;linux
shell是一个用C编写的程序,是用户使用Linux的桥梁;nginx
而日常说的shell就是指shell脚本,是一种为shell编写的脚本程序;c++
而shell还有另外一种概念,是指一种应用程序,这个应用程序提供了一个界面,用户经过这个界面访问操做系统内核的服务;
Ken Thompson的sh是第一种Unix Shell,Windows Explorer是一个典型的图形界面Shell;git
本文中说的shell,大部分指shell脚本,那就来看示例吧,想知道shell脚本是什么:正则表达式
#!/bin/sh
cd ~
mkdir jb_shell
cd jb_shell
for ((i=0; i<5; i++)); do
touch jb_$i.txt
done
复制代码
示例解释:shell
mkdir
,touch
都是系统自带的程序,通常都在/bin或/usr/bin目录下;
for
,do
,done
是sh
脚本语言的关键字;
shell编程跟java、Python编程同样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就能够了;
当前主流的操做系统都支持shell编程,本文档所述的shell编程是指Linux下的shell,讲的基本都是POSIX标准下的功能,因此,也适用于Unix及BSD(如Mac OS);
Linux默认安装就带了shell解释器;
Mac OS不只带了sh、bash这两个最基础的解释器,还内置了ksh、csh、zsh等不经常使用的解释器;
windows出厂时没有内置shell解释器,须要自行安装,为了同时能用grep, awk, curl等工具,最好装一个cygwin或者mingw来模拟linux环境。
即Bourne shell,POSIX(Portable Operating System Interface)标准的shell解释器,它的二进制文件路径一般是/bin/sh,由Bell Labs开发;
本文讲的是sh,若是你使用其它语言用做shell编程,请自行参考相应语言的文档。
Bash是Bourne shell的替代品,属GNU Project,二进制文件路径一般是/bin/bash;
业界一般混用bash、sh、和shell,好比你会常常在招聘运维工程师的文案中见到:熟悉Linux Bash编程,精通Shell编程。
在CentOS里,/bin/sh是一个指向/bin/bash的符号连接:
[root@centosraw ~]# ls -l /bin/*sh
-rwxr-xr-x. 1 root root 903272 Feb 22 05:09 /bin/bash
-rwxr-xr-x. 1 root root 106216 Oct 17 2012 /bin/dash
lrwxrwxrwx. 1 root root 4 Mar 22 10:22 /bin/sh -> bash
复制代码
但在Mac OS上不是,/bin/sh和/bin/bash是两个不一样的文件,尽管它们的大小只相差100字节左右:
iMac:~ wuxiao$ ls -l /bin/*sh
-r-xr-xr-x 1 root wheel 1371648 6 Nov 16:52 /bin/bash
-rwxr-xr-x 2 root wheel 772992 6 Nov 16:52 /bin/csh
-r-xr-xr-x 1 root wheel 2180736 6 Nov 16:52 /bin/ksh
-r-xr-xr-x 1 root wheel 1371712 6 Nov 16:52 /bin/sh
-rwxr-xr-x 2 root wheel 772992 6 Nov 16:52 /bin/tcsh
-rwxr-xr-x 1 root wheel 1103984 6 Nov 16:52 /bin/zsh
复制代码
理论上讲,只要一门语言提供了解释器(而不只是编译器),这门语言就能够胜任脚本编程,常见的解释型语言都是能够用做脚本编程的,如:Perl、Tcl、Python、PHP、Ruby;
Perl是最老牌的脚本编程语言了,Python这些年也成了一些linux发行版的预置解释器;
编译型语言,只要有解释器,也能够用做脚本编程,如C shell是内置的(/bin/csh),Java有第三方解释器Jshell,Ada有收费的解释器AdaScript;
以下是一个PHP Shell Script示例(假设文件名叫test.php):
#!/usr/bin/php
<?php
for ($i=0; $i < 10; $i++)
echo $i . "\n";
复制代码
执行:
/usr/bin/php test.php
复制代码
或者:
chmod +x test.php
./test.php
复制代码
打开文本编辑器,新建一个文件,扩展名为sh(sh表明shell),扩展名并不影响脚本执行;
输入一些代码,第一行通常是这样:
#!/bin/bash
复制代码
#!
是一个约定的标记,它告诉系统这个脚本须要什么解释器来执行;
运行Shell脚本有两种方法:
做为可执行程序
chmod +x test.sh
./test.sh
复制代码
注意,必定要写成./test.sh,而不是test.sh;
运行其它二进制的程序也同样,直接写test.sh,linux系统会去PATH里寻找有没有叫test.sh的,而只有/bin, /sbin, /usr/bin,/usr/sbin等在PATH里,你的当前目录一般不在PATH里;
因此写成test.sh是会找不到命令的,要用./test.sh告诉系统说,就在当前目录找;
这里会有疑问,#!/bin/bash
能够不写吗?
答案是能够的,若是这个系统是使用/bin/bash
做为解释器的话,就能够省去,或者使用解释器参数运行就不须要;
做为解释器参数 这种运行方式是,直接运行解释器,其参数就是shell脚本的文件名,如:
/bin/sh test.sh
bash test.sh
复制代码
定义变量时,变量名不须要加美圆符号($),如:
your_name="jb" # 这种状况,双引号可加可不加
your_name="jb test" #若是有空格要用双引号
复制代码
注意,变量名和等号之间不能有空格,这里踩坑屡次,切忌切忌,用其余语言的时候习惯空格了;
使用一个定义过的变量,只要在变量名前面加美圆符号便可,如:
your_name="jb"
echo $your_name
复制代码
echo ${your_name} 变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,好比下面这种状况:
for girl in 苍老师 前田 波多 大榄; do
echo "I like ${girl}Style"
done
复制代码
若是不给girl
变量加花括号,写成echo "I like ${girl}Style
",解释器就会把$girlStyle当成一个变量(其值为空),代码执行结果就不是想要的效果了;
已定义的变量,能够被从新定义,如:
your_name="jb"
echo $your_name
your_name="jbtest"
echo $your_name
复制代码
这样写是合法的,但注意,第二次赋值的时候不能写$your_name="jbtest"
,使用变量的时候才加美圆符;
以#
开头的行就是注释,会被解释器忽略;
sh里没有多行注释,只能每一行加一个#号。就像这样:
#--------------------------------------------
#jb test
复制代码
可是,若是有几十行的代码要临时注释,每个都价格#
号太麻烦了,那有没有骚操做了?
有的,就是利用:
跟<<
连个,那先来介绍这两个玩意:
:
冒号是一个空命令,能够认为与shell的内建命令true相同,它的返回值是0;
在while循环中 while : 与 while true 的做用是等效的; 在 if/then 中可做为占位符;
if conditions
then: #什么都不作
else
take action
fi
复制代码
<< tag
是将开始标记 tag 和结束标记 tag 之间的内容做为输入,tag
不是关键字,能够随意替换,只是要先后统一便可;
那另一种多行注释的方式以下:
:<<jbtest
echo "I am jb"
echo "I am jb"
echo "I am jb"
jbtest
复制代码
:
冒号空命令,啥都不作,<<
是将内容重定向输入,两个jbtest
(可任意替换,不是关键字)之间的内容经过<<
追加给冒号:
,可是:
冒号对它们啥都不作,就至关于没作任何处理和输出,就至关于注释了;
这操做,的确牛,可是会有兼容性问题,如注释的内容里面带有冒号的话,会报错;
字符串是shell编程中最经常使用最有用的数据类型,字符串能够用单引号,也能够用双引号,也能够不用引号;
str='this is jb'
复制代码
单引号字符串的限制:
your_name='jb'
str="Hello, I know your are \"$your_name\"! \n"
复制代码
your_name="jb"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
输出:hello, jb ! hello, jb !
复制代码
取字符串长度;
string="jb"
echo ${#string}
expr length $string
两个都是输出4,但通常用第一种较多;
复制代码
取特定长度的字符串内容;
string="jb is a jb"
echo ${string:0:4} # 输出jb i,从第0个位置开始提取4个字符串;
echo ${string:4} # 输出s a jb,从第4个位置开始提取字符串
echo ${string:(-6):3}
# 输出s a,负数表示从右开始计数,从右侧数起第6个位置提取3个字符串;
复制代码
找出具体字符串位置;
str="abc"
expr index $str "ab" # 输出:1
expr index $str "b" # 输出:2
expr index $str "x" # 输出:0,不存在则0
复制代码
str="abbc,def,ghi,abcjkl"
命令 | 意义&输出 |
---|---|
echo${str#a*c} |
输出,def,ghi,abcjkl 一个井号(#) 表示从左边截取掉最短的匹配 (这里把abbc字串去掉) |
echo ${str##a*c} |
输出jkl 两个井号(##) 表示从左边截取掉最长的匹配 (这里把abbc,def,ghi,abc字串去掉) |
echo ${str#"a*c"} |
输出abbc,def,ghi,abcjkl 由于str中没有"a*c"子串 |
echo ${str##"a*c"} |
输出abbc,def,ghi,abcjkl 同理 |
echo ${str#d*f} |
输出abbc,def,ghi,abcjkl |
echo ${str#*d*f} |
输出,ghi,abcjkl |
echo ${str%a*l} |
输出abbc,def,ghi, 一个百分号(%)表示从右边截取最短的匹配 |
echo ${str%%b*l} |
输出a 两个百分号表示(%%)表示从右边截取最长的匹配 |
echo ${str%a*c} |
输出abbc,def,ghi,abcjkl |
1个井号#
带一个数字,因此截取最短,2个井号则截取最长; 1个百分号%
只是从右侧开始算,同上;
也许上面有同窗会有疑问echo ${str#d*f}
,而什么会显示所有解决,由于这种方式是从头开始的,是字符串匹配的,真不智能了,所以列出其余能够截取字符串的方式:
格式 | 说明 |
---|---|
${string: start :length} |
从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符; |
${string: start} |
从 string 字符串的左边第 start 个字符开始截取,直到最后; |
${string: 0-start :length} |
从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符; |
${string: 0-start} |
从 string 字符串的右边第 start 个字符开始截取,直到最后; |
${string#*chars} |
从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的全部字符; |
${string##*chars} |
从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的全部字符; |
${string%*chars} |
从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的全部字符; |
${string%%*chars} |
从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的全部字符; |
str="apple, tree, apple tree"
echo ${str/apple/APPLE}
#替换第一次出现的apple,输出:APPLE, tree, apple tree
echo ${str//apple/APPLE}
# 替换全部apple,输出:APPLE, tree, APPLE tree
echo ${str/#apple/APPLE}
# 若是字符串str以apple开头,则用APPLE替换它,输出:APPLE, tree, apple tree
echo ${str/%apple/APPLE}
# 若是字符串str以apple结尾,则用APPLE替换它,输出:apple, tree, apple tree
复制代码
这里面也有明显的问题,就是若是想替换第2、第三个怎么办? 抱歉,是不行的,只能用sed
,下面会说起到;
数组中能够存放多个值。 Shell 只支持一维数组(不支持多维数组),初始化时不须要定义数组大小; 与大部分编程语言相似,数组元素的下标由0开始;
Shell 数组用括号来表示,元素用空格符号分割开,语法格式以下:
array_name=(value1 ... valuen)
arr_num=(1 2 3 4 5 )
arr_string=("abc" "edf" "sss")
复制代码
也可使用下标来定义数组:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
复制代码
下面两种方式都可
${#arr_number[*]}
${#arr_number[@]}
复制代码
例子:
arr_number=(1 2 3 4 5)
echo "数组元素个数为: ${#arr_number[*]}"
echo "数组元素个数为: ${#arr_number[@]}"
输出:5
复制代码
arr_number=(1 2 3 4 5)
echo "${#arr_number[2]}"
${数组名[下标]}
输出:1
复制代码
这里分两种状况: 指定的下标是存在的 直接替换新的指定值;
arr_number[2]=100,数组被修改成(1 2 100 4 5)
复制代码
指定的下标是不存在的 那新的赋值会添加后数组的尾部;
arr_number[100]=100,数组被修改成(1 2 100 4 5 100)
复制代码
清除某个元素:
unset arr_number[1]
# 这里清除下标为1的数组;
复制代码
清空整个数组:
unset arr_number
复制代码
分片访问形式为:${数组名[@或*]:开始下标:结束下标}, 注意,不包括结束下标元素的值;
${arr_number[@]:1:4}
# 这里分片访问从下标为1开始,元素个数为4,输出的是2 3 4 5
复制代码
形式为:${数组名[@或*]/数值/新值}
${arr_number[@]/2/98}
#就是把2替换成98,输出:1 98 3 4 5
复制代码
for v in ${arr_number[@]}; do
echo $v;
done
复制代码
通常使用脚本,都须要向脚本传递参数,那shell获取参数的格式是$n
, n表明的是数据,1为执行脚本的第一个参数,2为执行脚本的第二位参数;
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
复制代码
执行脚本:
$ bash test.sh one two three
Shell 传递参数实例!
执行的文件名:test.sh
第一个参数为:one
第二个参数为:two
第三个参数为:three
复制代码
还有几个特殊字符,这边不展开说明,自行了解吧;
参数处理 | 说明 |
---|---|
$# |
传递到脚本的参数个数 |
$* |
以一个单字符串显示全部向脚本传递的参数。如"$*"用「"」括起来的状况、以"$1 ![]() |
$$ |
脚本运行的当前进程ID号 |
$! |
后台运行的最后一个进程的ID号 |
$@ |
与$*相同,可是使用时加引号,并在引号中返回每一个参数。 |
如"$@"用「"」括起来的状况、以"$1" "n" 的形式输出全部参数。
$-
|显示Shell使用的当前选项,与set命令功能相同。 $?
|显示最后命令的退出状态。0表示没有错误,其余任何值代表有错误。
若是脚本传参有N个,可是又不想一个一个$1
、 $2
这样判断,那怎么办?
while [ -n "$1" ]
do
case "$1" in
-jb) echo "jb";;
-jb1) echo "jb1";;
-jb2) echo "jb2";;
-jb3) echo "jb3";;
*) echo "over" ;;
esac
shift
done
复制代码
运行的结果:
$ bash test.sh -jb -jb2 -jb3 -jb4
jb
jb2
jb3
over
复制代码
在 Bash 中,管道符使用"丨"表明; 管道符也是用来链接多条命令的,如"命令1丨命令2";
好比:
adb shell ps | grep com
复制代码
就会输出一堆喊出com的内容,也就是利用了管道符号;
条件判断的做用 判断某需求是否知足;
返回类型
格式
测试选项 | 做用 |
---|---|
-b 文件 | 判断该文件是否存在,而且是块设备文件 |
-c 文件 | 判断该文件是否存在,而且是字符设备文件 |
-d 文件 | 判断该文件是否存在,而且是目录 |
-e 文件 | 判断该文件是否存在 |
-f 文件 | 判断该文件是否存在,而且是普通文件 |
-L 文件 | 判断该文件是否存在,而且是符号连接文件 |
-p 文件 | 判断该文件是否存在,而且是管道文件 |
-s 文件 | 判断该文件是否存在,而且非空 |
-S 文件 | 判断该文件是否存在,而且是套接字文件 |
利用 &&
和 ||
判断文件是不是目录
$ [ -d test ] && echo 'yes' || echo 'no'
yes
$ [ -d test1 ] && echo 'yes' || echo 'no'
no
复制代码
测试选项 | 做用 |
---|---|
-r 文件 | 判断该文件是否存在,而且当前用户拥有读权限 |
-w 文件 | 判断该文件是否存在,而且当前用户拥有写权限 |
-x 文件 | 判断该文件是否存在,而且当前用户拥有执行权限 |
-u 文件 | 判断该文件是否存在,而且拥有SUID权限 |
-g 文件 | 判断该文件是否存在,而且拥有SGID权限 |
-k 文件 | 判断该文件是否存在,而且拥有SBit权限 |
判断文件权限
$ [ -r test ] && echo yes || echo no
yes
$ [ -w test ] && echo yes || echo no
yes
$ [ -x test ] && echo yes || echo no
yes
复制代码
测试选项 | 做用 |
---|---|
文件1 -nt 文件2 | 判断文件1的修改时间是否比文件2的新 |
文件1 -ot 文件2 | 判断文件1的修改时间是否比文件2的旧 |
文件1 -ef 文件2 | 判断文件1和文件2的Inode号是否一致,能够理解为两个文件是否为同一个文件。这适用于判断硬连接很好的方法 |
比较两个文件的最后修改时间
$ touch jb1; sleep 5; touch jb22
$ ll jb*
-rw-r--r-- 1 jb 197121 0 12月 11 15:17 jb
-rw-r--r-- 1 jb 197121 0 12月 11 15:17 jb1
-rw-r--r-- 1 jb 197121 0 12月 11 15:17 jb22
复制代码
jb@LAPTOP-2R0431R1 MINGW64 /c
$ [ jb1 -ot jb22 ] && echo yes || echo no
yes
jb@LAPTOP-2R0431R1 MINGW64 /c
$ [ jb1 -nt jb22 ] && echo yes || echo no
no
复制代码
测试选项 | 做用 |
---|---|
整数1 -eq 整数2 | 判断整数1是否等于整数2 |
整数1 -ne 整数2 | 判断整数1是否不等于整数2 |
整数1 -gt 整数2 | 判断整数1是否大于整数2 |
整数1 -lt 整数2 | 判断整数1是否小于整数2 |
整数1 -ge 整数2 | 判断整数1是否大于等于整数2 |
整数1 -le 整数2 | 判断整数1是否小于等于整数2 |
测试选项 | 做用 |
---|---|
-z 字符串 | 判断字符串是否为空 |
-n 字符串 | 判断字符串是否为非空 |
字符串1 == 字符串2 | 判断字符串1和字符串2是否相等 |
字符串1 != 字符串2 | 判断字符串1和字符串2是否不相等 |
$ a=111
$ b=222
$ [ "$a" == "$b" ] && echo yes || echo no
no
复制代码
测试选项 | 做用 |
---|---|
判断1 -a 判断2 | 逻辑与,判断1 和 判断2都为真,最终结果才为真 |
判断1 -o 判断2 | 逻辑或,判断1 和 判断2有一个为真,最终结果就为真 |
! 判断 | 逻辑非,使原始的判断式取反 |
if condition
then
command1
command2
...
commandN
fi
复制代码
写成一行(适用于终端命令提示符):
if `ps -ef | grep ssh`; then echo hello; fi
复制代码
末尾的fi就是if倒过来拼写,对成对出现的;
if condition
then
command1
command2
...
commandN
else
command
fi
复制代码
if condition1
then
command1
elif condition2
command2
else
commandN
fi
复制代码
在上面的示例里看到过:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
复制代码
写成一行:
for var in item1 item2 ... itemN; do command1; command2… done;
复制代码
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;
while condition
do
command
done
复制代码
while :
do
command
done
复制代码
或者
while true
do
command
done
复制代码
或者
for (( ; ; ))
复制代码
until 循环执行一系列命令直至条件为 true 时中止; until 循环与 while 循环在处理方式上恰好相反;
通常 while 循环优于 until 循环,但在某些时候—也只是极少数状况下,until 循环更加有用。
until condition
do
command
done
复制代码
Shell case语句为多选择语句。能够用case语句匹配一个值与一个模式,若是匹配成功,执行相匹配的命令。
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
复制代码
须要一个esac(就是case反过来)做为结束标记,每一个case分支用右圆括号用两个分号表示break;
break命令容许跳出全部循环(终止执行后面的全部循环)。
ontinue命令与break命令相似,只有一点差异,它不会跳出全部循环,仅仅跳出当前循环。
shell能够自定义函数,而后在shell脚本中随意调用;
shell函数定义的格式:
function 函数名 () {
to do..
return -n
}
复制代码
function jb1 () { #前面的function是声明一个函数 名字叫 jb1 ()
echo "jb1" # 执行操做,输出jb1
}
function jb2 () {
echo "jb2"
}
jb3() {
echo "jb3"
}
jb1 # 调用jb1函数
jb2
jb3
复制代码
function jb () {
echo 个人名字叫: $1
}
jb $1
复制代码
运行:
$ bash test.sh hahhahha
个人名字叫: hahhahha
复制代码
function CDAN(){
cat << yankerp
+------------------------------------------------+
| |
| _o0o_ 1. 安装Nginx |
| 08880 2. 安装Apache |
| 88"."88 3. 安装MySQL |
| (|-_-|) 4. 安装PHP |
| 0\=/0 5. 部署LNMP环境 |
| __/ \__ 6. 安装zabbix监控 |
| ‘\ ///‘ 7. 退出此管理程序 |
| / Linux一键 \ 8. 关闭计算机 |
| || Server || ====================== |
| \ //// 一键安装服务 |
| ||| i i i ||| by Yankerp |
| ___ ___ ====================== |
|___‘. /--.--\ .‘___ |
+------------------------------------------------+
yankerp
}
CDAN
LOG_DIR=/usr/local/src
read -p "请您输入1-8任意数值:" NUM
if [ ${#NUM} -ne 1 ]
then
echo "请您输入1|2|3|4|5|6|7|8"
exit 1
fi
expr $NUM + 1 &>/dev/null
if [ "$?" -ne 0 ]
then
echo "请您输入数值!"
exit 1
fi
if [ "$NUM" -gt 8 ];then
echo "请您输入比8小的数值"
exit 1
elif [ "$NUM" -eq 0 ];then
echo "请您输入比0大的数值"
exit 1
fi
######################
function Nginx_DIR() {
yum install -y gcc gcc-c++ pcre-devel zlib-devel openssl-devel &>/dev/null
if [ $? -eq 0 ]
then
cd $LOG_DIR && wget http://nginx.org/download/nginx-1.12.2.tar.gz &>/dev/null && useradd -M -s /sbin/nologin nginx && \
tar zxf nginx-1.12.2.tar.gz && cd nginx-1.12.2/ && \
./configure --prefix=/usr/local/nginx --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module --with-pcre --with-http_ssl_module --with-http_gzip_static_module --user=nginx &>/dev/null && make &>/dev/null && make install &>/dev/null
fi
if [ -e /usr/local/nginx/sbin/nginx ];then
ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ && nginx && echo "Nginx安装并启动成功!!!"
fi
}
if [ $NUM -eq 1 ]
then
echo "开始安装Nginx请稍等..." && Nginx_DIR
fi
复制代码
输出:
上面说了流程,这里就介绍一个比较特殊的流程控制:select
select的格式以下:
select name [in list ]
do
循环体命令
done
复制代码
从格式上看,跟for的格式相似; select 循环主要用于建立菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入;
用户输入菜单列表中的某个选项,执行响应的命令,而输入的内容会被保存在内置变量REPLY 里;
select 是个无限循环,所以要记住用break 命令退出循环,或用exit 命令终止脚本。也能够按ctrl+c 退出循环。
例子:
text="Please select a number: "
select name in jb1 jb2 jb3 jb4
do
case $name in
jb1)
echo "Hello, jb1."
;;
jb2)
echo "Hello,jb2."
;;
jb3)
echo "Hello, jb3."
;;
jb4)
echo "Hello, jb4."
;;
*)
echo "Sorry, there is no such person."
;;
esac
done
复制代码
结果:
在Linux系统中,一切设备都看做文件。 而每打开一个文件,就有一个表明该打开文件的文件描述符。 程序启动时默认打开三个I/O设备文件:
文件描述符 | 缩写 | 描述 |
---|---|---|
0 | STDIN | 标准输入 |
1 | STDOUT | 标准输出 |
2 | STDERR | 标准错误 |
默认状况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
若是但愿 stderr 重定向到 file,能够这样写:
$ command 2 > file
复制代码
若是但愿 stderr 追加到 file 文件末尾,能够这样写:
$ command 2 >> file
复制代码
2
表示标准错误文件(stderr)。
若是但愿将 stdout 和 stderr 合并后重定向到 file,能够这样写:
$ command > file 2>&1
复制代码
或者
$ command >> file 2>&1
复制代码
若是但愿对 stdin 和 stdout 都重定向,能够这样写:
$ command < file1 >file2
复制代码
command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。
sh脚本结合系统命令便有了强大的威力,在字符处理领域,有grep、awk、sed三剑客,grep负责找出特定的行,awk能将行拆分红多个字段,sed则能够实现更新插入删除等写操做。
ps命令用来列出系统中当前运行的那些进程,但ps 提供的hi进程的一次性的查看,它所提供的查看结果并非动态连续的;
若是想对进程时间监控,应该用 top 工具。
对系统中进程进行监测控制,查看状态,内存,CPU的使用状况,使用命令:/bin/ps
ps 命令就是最基本同时也是很是强大的进程查看命令; 使用该命令能够肯定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等。
使用方式:ps [options] [--help] 说明:显示瞬间行程 (process) 的动态 参数:见下方
命令 | 含义 |
---|---|
ps a | 显示现行终端机下的全部程序,包括其余用户的程序 |
ps -A | 显示全部进程 |
ps c | 列出程序时,显示每一个程序真正的指令名称 |
ps -e | 此参数的效果和指定"A"参数相同 |
ps e | 列出程序时,显示每一个程序所使用的环境变量 |
ps f | 用ASCII字符显示树状结构,表达程序间的相互关系 |
ps -H | 显示树状结构,表示程序间的相互关系 |
ps -N | 显示全部的程序,除了执行ps指令终端机下的程序以外 |
ps s | 采用程序信号的格式显示程序情况 |
ps S | 列出程序时,包括已中断的子程序资料 |
ps -t<编号> | 指定编号,并列出属于该程序的情况 |
ps u | 以用户为主的格式来显示程序情况 |
ps x | 显示全部程序,不以程序来区分 |
最经常使用的方法是ps -aux
,而后再利用一个管道符号导向到grep去查找特定的进程,而后再对特定的进程进行操做。
ps -aux | grep com.jbtest
#这样就会把com.jbtest相关的进程信息所有列出;
复制代码
基本PS使用
$ps
复制代码
名称 | 含义 |
---|---|
PID | 运行着的命令(CMD)的进程编号 |
TTY | 命令所运行的位置(终端) |
TIME | 运行着的该命令所占用的CPU处理时间 |
CMD | 该进程所运行的命令 |
列出目前全部的正在内存当中的程序
$ ps -aux
复制代码
名称 | 含义 |
---|---|
USER | 用户名 |
UID | 用户ID(User ID) |
PID | 进程ID(Process ID) |
PPID | 父进程的进程ID(Parent Process id) |
SID | 会话ID(Session id) |
%CPU | 进程的cpu占用率 |
%MEM | 进程的内存占用率 |
VSZ | 进程所使用的虚存的大小(Virtual Size) |
RSS | 进程使用的驻留集大小或者是实际内存的大小,Kbytes字节。 |
TTY | 与进程关联的终端(tty) |
STAT | 进程的状态:进程状态使用字符表示的(STAT的状态码) |
START | 进程启动时间和日期 |
TIME | 进程使用的总cpu时间 |
COMMAND | 正在执行的命令行命令 |
关于STAT,能够经过截图看到有不少字符,具体的含义以下:
名称 | 含义 |
---|---|
R | 运行 Runnable (on run queue) 正在运行或在运行队列中等待。 |
S | 睡眠 Sleeping 休眠中, 受阻, 在等待某个条件的造成或接受到信号。 |
I | 空闲 Idle |
Z | 僵死 Zombie(a defunct process) 进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放。 |
D | 不可中断 Uninterruptible sleep (ususally IO) 收到信号不唤醒和不可运行, 进程必须等待直到有中断发生。 |
T | 终止 Terminate 进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后中止运行运行。 |
P | 等待交换页 |
W | 无驻留页 has no resident pages 没有足够的记忆体分页可分配。 |
X | 死掉的进程 |
< | 高优先级进程 高优先序的进程 |
N | 低优先 级进程 低优先序的进程 |
L | 内存锁页 Lock 有记忆体分页分配并缩在记忆体内 |
s | 进程的领导者(在它之下有子进程); |
l | 多进程的(使用 CLONE_THREAD, 相似 NPTL pthreads) |
+ | 位于后台的进程组 |
能够用 | 管道和 more 链接起来分页查看
ps -aux |more
复制代码
能够用 | 管道和 grep 过滤
ps -aux |grep ps
复制代码
把全部进程显示出来,并输出到jb.txt文件
ps -aux > jb.txt
复制代码
输出指定的字段
ps -o pid,ppid,pgrp,session,tpgid,comm
复制代码
根据 CPU 使用来升序排序
ps -aux --sort -pcpu | less
复制代码
根据 内存使用 来升序排序
ps -aux --sort -pmem | less
复制代码
树形显示进程
pstree
复制代码
经过进程名和PID过滤 使用 -C 参数,后面跟你要找的进程的名字。好比想显示一个名为getty的进程的信息,就可使用下面的命令:
ps -C getty
复制代码
显示全部进程信息,连同命令行
ps -ef
复制代码
grep命令用于查找文件里符合条件的字符串;
通常是结合管道|来使用,固然也支持单独带参使用;
grep 更适合单纯的查找或匹配文本;
grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>][-d<进行动做>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]
复制代码
参数 | 含义 |
---|---|
-a 或 --text | 不要忽略二进制的数据。 |
-A<显示行数> 或 --after-context=<显示行数> | 除了显示符合范本样式的那一列以外,并显示该行以后的内容。 |
-b 或 --byte-offset | 在显示符合样式的那一行以前,标示出该行第一个字符的编号。 |
-B<显示行数> 或 --before-context=<显示行数> | 除了显示符合样式的那一行以外,并显示该行以前的内容。 |
-c 或 --count | 计算符合样式的列数。 |
-C<显示行数> 或 --context=<显示行数>或-<显示行数> | 除了显示符合样式的那一行以外,并显示该行以前后的内容。 |
-d <动做> 或 --directories=<动做> | 当指定要查找的是目录而非文件时,必须使用这项参数,不然grep指令将回报信息并中止动做。 |
-e<范本样式> 或 --regexp=<范本样式> | 指定字符串作为查找文件内容的样式。 |
-E 或 --extended-regexp | 将样式为延伸的普通表示法来使用。 |
-f<规则文件> 或 --file=<规则文件> | 指定规则文件,其内容含有一个或多个规则样式,让grep查找符合规则条件的文件内容,格式为每行一个规则样式。 |
-F 或 --fixed-regexp | 将样式视为固定字符串的列表。 |
-G 或 --basic-regexp | 将样式视为普通的表示法来使用。 |
-h 或 --no-filename | 在显示符合样式的那一行以前,不标示该行所属的文件名称。 |
-H 或 --with-filename | 在显示符合样式的那一行以前,表示该行所属的文件名称。 |
-i 或 --ignore-case | 忽略字符大小写的差异。 |
-l 或 --file-with-matches | 列出文件内容符合指定的样式的文件名称。 |
-L 或 --files-without-match | 列出文件内容不符合指定的样式的文件名称。 |
-n 或 --line-number | 在显示符合样式的那一行以前,标示出该行的列数编号。 |
-q 或 --quiet或--silent | 不显示任何信息。 |
-r 或 --recursive | 此参数的效果和指定"-d recurse"参数相同。 |
-s 或 --no-messages | 不显示错误信息。 |
-v 或 --revert-match | 显示不包含匹配文本的全部行。 |
-V 或 --version | 显示版本信息。 |
-w 或 --word-regexp | 只显示全字符合的列。 |
-x --line-regexp | 只显示全列符合的列。 |
-y | 此参数的效果和指定"-i"参数相同。 |
上面说的不少参数,但通常来讲,经常使用的很是少,那就来一块儿看看经常使用的命令吧;
能够用 | 管道和 grep 过滤 查找指定进程
ps -aux |grep ps
复制代码
在当前目录中,查找后缀有 jb
字样的文件中包含 jbtest
字符串的文件
grep jbtest *jb
复制代码
上面这种用法,当目录下有文件夹,就会报错,grep: sound: Is a directory
,由于grep默认只在当前目录,若是须要递归查找,则须要使用-r
;
grep -r jbtest /etc/jb
#这样就会输出jb目录下的全部文件包含jbtest的文件及内容
复制代码
从文件中读取关键词进行搜索
cat jb.txt | grep -f jb2.txt
#意思是根据grep的结果来进行对jb.txt的过滤
[root@localhost test]# cat jb.txt
hnlinux
peida.cnblogs.com
ubuntu
ubuntu linux
redhat
Redhat
linuxmint
[root@localhost test]# cat jb2.txt
linux
Redhat
[root@localhost test]# cat jb.txt | grep -f jb2.txt
hnlinux
ubuntu linux
Redhat
linuxmint
复制代码
显示包含ed或者at字符的内容行
cat jb.txt |grep -E "ed|at"
复制代码
正则匹配全部以字母 “b” 开头、字母 “t” 结尾的三个字符的单词
grep '\<b.t\>' jb.txt
复制代码
awk是什么 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤其强大;
简单来讲awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各类分析处理;
awk
更适合格式化文本,对文本进行较复杂格式处理;
awk [选项参数] 'script' var=value file(s)
or
awk [选项参数] -f scriptfile var=value file(s)
复制代码
字符 | 含义 |
---|---|
F fs | 表示指定输入文件分隔符,fs是一个字符串或者是一个正则表达式,如-F; |
-v var=value | 表示赋值一个用户定义变量; |
-f scriptfile | 从脚本文件中读取awk命令; |
-W compact | 在兼容模式下运行awk; |
-W copyleft | 打印简短的版权信息; |
-W help | 打印所有awk选项和每一个选项的简短说明; |
-W lint | 打印不能向传统unix平台移植的结构的警告; |
-W lint-old | 打印关于不能向传统unix平台移植的结构的警告; |
-W posix | 打开兼容模式,但有如下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行做为一个域分隔符;操做符**和**=不能代替^和^=;fflush无效。 |
-W re-interval | 容许间隔正则表达式的使用,如括号表达式[[:alpha:]]; |
-W source program-text | 使用program-text做为源代码; |
-W version | 打印bug报告信息的版本; |
看不懂?不要紧,一块儿来看看怎么用吧~
awk '{pattern + action}' {filenames}
# 注意,只能用单引号
复制代码
这里来用一个例子展开说明,jb.txt:
Tom is a man who cheats and plays with women's feelings.
He goes to work every day to fish for fish.
He lives in a muddle through life.
复制代码
用法1
awk '{[pattern] action}' {filenames}
# 行匹配语句 awk '' 只能用单引号
复制代码
例子:
awk '{print $1,$4}' jb.txt
# 每行按空格或TAB分割,输出文本中的一、4项
Tom man
He work
He a
# 格式化输出
awk '{printf "%-8s %-10s\n",$1,$4}' jb.txt
------------------------------------------
Tom man
He work
He a
复制代码
用法二
awk -F
#-F至关于内置变量FS, 指定分割字符
复制代码
例子:
awk -F, '{print $1,$2}' jb.txt
-----------------------------------
Tom is a man who cheats and plays with women's feelings.
He goes to work every day to fish for fish.
He lives in a muddle through life.
#使用内建变量
awk 'BEGIN{FS=","} {print $1,$2}' jb.txt
---------------------------------------------
Tom is a man who cheats and plays with women's feelings.
He goes to work every day to fish for fish.
He lives in a muddle through life.
#使用多个分隔符.先使用空格分割,而后对分割结果再使用","分割
awk -F '[ ,]' '{print $1,$2,$5}' jb.txt
--------------------------------------------------------
Tom is who
He goes every
He lives muddle
复制代码
用法三
awk -v
# 设置变量
复制代码
例子:
awk -va=1 '{print $1,$1+a}' jb.txt
---------------------------------------------
Tom 1
He 1
He 1
#这里可能会有疑问,为何变量+1=1?
原来是由于,将变量经过”+”链接运算,自动强制将字符串转为整型。
非数字变成0,发现第一个非数字字符,后面自动忽略。
awk -va=1 -vb=s '{print $1,$1+a,$1b}' jb.txt
---------------------------------------------
Tom 1 Toms
He 1 Hes
He 1 Hes
复制代码
用法四
awk -f {awk脚本} {文件名}
例子:
awk -f jb.awk log.txt
复制代码
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= |
赋值 |
?: |
C条件表达式 |
\|\| |
逻辑或 |
&& |
逻辑与 |
~ ~! |
匹配正则表达式和不匹配正则表达式 |
< <= > >= != == |
关系运算符 |
空格 |
链接 |
+ - |
加,减 |
* / % |
乘,除与求余 |
+ - ! |
一元加,减和逻辑非 |
^ *** |
求幂 |
++ -- |
增长或减小,做为前缀或后缀 |
$ |
字段引用 |
in |
数组成员 |
jb.txt:
1Tom is a man who cheats and plays with women's feelings.
3He goes to work every day to fish for fish.
5He lives in a muddle through life.
复制代码
过滤第一列大于2的行
awk '$1>2' jb.txt
---------------------------------------
3He goes to work every day to fish for fish.
5He lives in a muddle through life.
复制代码
过滤第一列等于3的行
awk '$1==3 {print $1,$3}' jb.txt
复制代码
过滤第一列大于2而且第二列等于'Are'的行
awk '$1>2 && $2=="Are" {print $1,$2,$3}' jb.txt
复制代码
变量 | 描述 |
---|---|
$n |
当前记录的第n个字段,字段间由FS分隔 |
$0 |
完整的输入记录 |
ARGC |
命令行参数的数目 |
ARGIND |
命令行中当前文件的位置(从0开始算) |
ARGV |
包含命令行参数的数组 |
CONVFMT |
数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
ERRNO |
最后一个系统错误的描述 |
FIELDWIDTHS |
字段宽度列表(用空格键分隔) |
FILENAME |
当前文件名 |
FNR |
各文件分别计数的行号 |
FS |
字段分隔符(默认是任何空格) |
IGNORECASE |
若是为真,则进行忽略大小写的匹配 |
NF |
一条记录的字段的数目 |
NR |
已经读出的记录数,就是行号,从1开始 |
OFMT |
数字的输出格式(默认值是%.6g) |
OFS |
输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 |
ORS |
输出记录分隔符(默认值是一个换行符) |
RLENGTH |
由match函数所匹配的字符串的长度 |
RS |
记录分隔符(默认是一个换行符) |
RSTART |
由match函数所匹配的字符串的第一个位置 |
SUBSEP |
数组下标分隔符(默认值是/034) |
awk '{print $1,$2,$5}' OFS=" $ " jb.txt
---------------------------------------
1Tom $ is $ who
3He $ goes $ every
5He $ lives $ muddle
awk '{print NR,FNR,$1,$2,$3}' jb.txt
---------------------------------------
1 1 1Tom is a
2 2 3He goes to
3 3 5He lives in
复制代码
# 输出第1列包含 "He",并打印第1列与第2列
awk '$1 ~ /He/ {print $1,$2}' jb.txt
--------------------------------------
3He goes
5He lives
# 输出包含"is" 的行
awk '/is/ ' jb.txt
---------------------------------------------
1Tom is a man who cheats and plays with women's feelings.
3He goes to work every day to fish for fish.
复制代码
~ 表示模式开始,// 中是模式。
awk 'BEGIN{IGNORECASE=1} /he/' jb.txt
---------------------------------------------
1Tom is a man who cheats and plays with women's feelings.
3He goes to work every day to fish for fish.
5He lives in a muddle through life.
复制代码
#是按第6例分隔文件,其中的NR!=1表示不处理表头
awk 'NR!=1{print > $6}' jb.txt
#指定的列输出到文件
awk 'NR!=1{print $4,$5 > $6}' jb.txt
复制代码
上面演示的例子,会看到BEGIN跟END的关键字,这里来介绍下:
jb.txt:
Marry 2143 78 84 77
Jack 2321 66 78 45
Tom 2122 48 77 71
Mike 2537 87 97 95
Bob 2415 40 57 62
复制代码
#!/bin/awk -f
#运行前
BEGIN {
math = 0
english = 0
computer = 0
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
复制代码
运行结果:
awk -f test.sh jb.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
复制代码
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
复制代码
更多有关awk详细的内容,请跳转到runoob、gnu查看,谢谢;
sed是一款流编辑工具,用来对文本进行过滤与替换工做; sed经过输入读取文件内容,但一次仅读取一行内容进行某些指令处理后输出,sed更适合于处理大数据文件;
sed在处理文本文件的时候,会在内存上建立一个模式空间,而后把这个文件的每一行调入模式空间用相应的命令处理,处理完输出;接着处理下一行,直到最后;
vim须要通知处理文件的哪几行才会去处理,sed默认会处理文件的全部行,除非你告诉它不处理哪几行;
sed [options] 'command' file(s)
sed [options] -f scriptfile file(s)
复制代码
options
参数 | 含义 |
---|---|
-e<script>或--expression=<script> |
以选项中的指定的script来处理输入的文本文件; |
-f<script文件>或--file=<script文件> |
以选项中指定的script文件来处理输入的文本文件; |
-h或--help |
显示帮助; |
-n或--quiet或——silent |
仅显示script处理后的结果; |
-V或--version |
显示版本信息; |
参数 指定待处理的文本文件列表;
参数 | 含义 |
---|---|
a |
在当前行下面插入文本; |
i |
在当前行上面插入文本; |
c |
把选定的行改成新的文本; |
d |
删除,删除选择的行; |
D |
删除模板块的第一行; |
s |
替换指定字符; |
h |
拷贝模板块的内容到内存中的缓冲区; |
H |
追加模板块的内容到内存中的缓冲区; |
g |
得到内存缓冲区的内容,并替代当前模板块中的文本; |
G |
得到内存缓冲区的内容,并追加到当前模板块文本的后面; |
l |
字符的清单; |
n |
读取下一个输入行,用下一个命令处理新的行而不是用第一个命令; |
N |
追加下一个输入行到模板块后面并在两者间嵌入一个新行,改变当前行号码; |
p |
打印模板块的行; |
P(大写) |
打印模板块的第一行; |
q |
退出Sed; |
b lable |
分支到脚本中带有标记的地方,若是分支不存在则分支到脚本的末尾; |
r file |
从file中读行; |
t label |
if分支,从最后一行开始,条件一旦知足或者T,t命令,将致使分支到带有标号的命令处,或者到脚本的末尾; |
T label |
错误分支,从最后一行开始,一旦发生错误或者T,t命令,将致使分支到带有标号的命令处,或者到脚本的末尾; |
w file |
写并追加模板块到file末尾; |
W file |
写并追加模板块的第一行到file末尾; |
! |
表示后面的命令对全部没有被选定的行发生做用; |
= |
打印当前行号码; |
# |
把注释扩展到下一个换行符之前; |
参数 | 含义 |
---|---|
g |
表示行内全面替; |
p |
表示打印行; |
w |
表示把行写入一个文件; |
x |
表示互换模板块中的文本和缓冲区中的文本; |
y |
表示把一个字符翻译为另外的字符(可是不用于正则表达式); |
\1 |
子串匹配标记; |
& |
已匹配字符串标记; |
参数 | 含义 |
---|---|
^ |
匹配行开始,如:/^sed/匹配全部以sed开头的行; |
$ |
匹配行结束,如:/sed$/匹配全部以sed结尾的行; |
. |
匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d; |
* |
匹配0个或多个字符,如:/*sed/匹配全部模板是一个或多个空格后紧跟sed的行; |
[] |
匹配一个指定范围内的字符,如/[ss]ed/匹配sed和Sed; |
[^] |
匹配一个不在指定范围内的字符,如:/[^A-RT-Z]ed/匹配不包含A-R和T-Z的一个字母开头,紧跟ed的行; |
\(..\) |
匹配子串,保存匹配的字符,如s/(love)able/\1rs,loveable被替换成lovers; |
& |
保存搜索字符用来替换其余字符,如s/love/&/,love这成love; |
\< |
匹配单词的开始,如:/<love/匹配包含以love开头的单词的行。 |
\> |
匹配单词的结束,如/love>/匹配包含以love结尾的单词的行; |
x\{m\} |
重复字符x,m次,如:/0{5}/匹配包含5个0的行; |
x\{m,\} |
重复字符x,至少m次,如:/0{5,}/匹配至少有5个0的行; |
x\{m,n\} |
重复字符x,至少m次,很少于n次,如:/0{5,10}/匹配5~10个0的行; |
看到这里,是否懵逼了?
别看了,直接看实战吧;
jb.txt的内容:
jb testing now
复制代码
替换文本中的字符串
sed 's/jb/jb2/' jb.txt
--------------------------
jb2 testing now
复制代码
-n选项和p命令一块儿使用表示只打印那些发生替换的行:
sed -n 's/jb/jb2/p' jb.txt
复制代码
直接编辑文件选项-i,会匹配file文件中每一行的第一个jb替换为jb2:
sed -i 's/jb/jb2/g' jb.txt
复制代码
插入
方法1:
用sed的i
命令在第一行前面插入便可,加上 -i
选项直接操做文件。
若是不加只是打印不会写入文件。
例如,文件头部添加一行字符:
sed -i '1i\3a0000' jb.txt
复制代码
方法2:
使用-e和-i选项;
jb.txt指定行(好比第三行)后面添加一行内容,好比“3a0000”:
sed -e "/3/a 3a0000" -i jb.txt
例子:
sed -i '2iabc' jb.txt
复制代码
在jb.txt文件的第2行的上面插入abc,abc所行为第2行,原来行变成了第3行!
注意在行数后面的字母i!!!
sed -i '2aabc' jb.txt
复制代码
jb.txt文件的第2行的下面插入abc,abc所在行为第3行,原来行不变任然为第2行。
注意在行数后面的字母a!!
在a.txt的第88行插入文件b.txt
sed -i '88 r b.file' a.file
#若是不知道行号,能够用正則匹配
sed -i '/regex/ r b.txt' a.txt # regex是正则表达式
复制代码
若是不改变源文件,能够去掉-i开关,修改会输出到STDOUT!!
全面替换标记g
使用后缀 /g 标记会替换每一行中的全部匹配:
sed 's/jb/jb2/g' jb.txt
复制代码
当须要从第N处匹配开始替换时,可使用 /Ng:
$ echo jbjbjbjb | sed 's/jb/jbtest/2g'
jbjbtestjbtestjbtest
复制代码
定界符
以上命令中字符 / 在sed中做为定界符使用,也可使用任意的定界符:
sed 's:test:TEXT:g'
sed 's|test|TEXT|g'
复制代码
定界符出如今样式内部时,须要进行转义:
sed 's/\/bin/\/usr\/local\/bin/g'
复制代码
通常来讲,/
:
这种经常使用的符号都须要转义;
删除操做:d命令
删除空白行:
sed '/^$/d' jb.txt
复制代码
删除文件的第2行:
sed '2d' jb.txt
复制代码
删除文件的第2行到末尾全部行:
sed '2,$d' jb.txt
复制代码
删除文件最后一行:
sed '$d' jb.txt
复制代码
删除文件中全部开头是test的行:
sed '/^test/'d jb.txt
复制代码
已匹配字符串标记&
正则表达式 \w+ 匹配每个单词,使用 [&] 替换它,& 对应于以前所匹配到的单词:
echo this is a test line | sed 's/\w\+/[&]/g'
---------------------------------------------
[this] [is] [a] [test] [line]
复制代码
全部以192.168.0.1开头的行都会被替换成它自已加localhost:
sed 's/^192.168.0.1/&localhost/' jb.txt
192.168.0.1localhost
复制代码
子串匹配标记\1
匹配给定样式的其中一部分:
echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
----------------------------------------------------
this is 7 in a number
复制代码
命令中 digit 7,被替换成了 7。
样式匹配到的子串是 7,(..) 用于匹配子串,对于匹配到的第一个子串就标记为 \1,依此类推匹配到的第二个结果就是 \2,例如:
echo aaa BBB | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
---------------------------------------------------------
BBB aaa
复制代码
love被标记为1,全部loveable会被替换成lovers,并打印出来:
sed -n 's/\(love\)able/\1rs/p' jb.txt
复制代码
组合多个表达式
sed '表达式' | sed '表达式'
等价于:
sed '表达式; 表达式'
复制代码
引用
sed表达式可使用单引号来引用,可是若是表达式内部包含变量字符串,就须要使用双引号。
test=hello
echo hello WORLD | sed "s/$test/HELLO"
HELLO WORLD
复制代码
选定行的范围:,(逗号)
全部在模板test和check所肯定的范围内的行都被打印:
sed -n '/test/,/check/p' jb.txt
复制代码
打印从第5行开始到第一个包含以test开始的行之间的全部行:
sed -n '5,/^test/p' jb.txt
复制代码
对于模板test和west之间的行,每行的末尾用字符串aaa bbb替换:
sed '/test/,/west/s/$/aaa bbb/' jb.txt
复制代码
多点编辑:e命令
·-e
选项容许在同一行里执行多条命令:
sed -e '1,5d' -e 's/test/check/' jb.txt
复制代码
上面sed表达式的第一条命令删除1至5行, 第二条命令用check替换test。
命令的执行顺序对结果有影响。
若是两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果。
和 -e
等价的命令是 --expression
:
sed --expression='s/test/check/' --expression='/love/d' jb.txt
复制代码
从文件读入:r命令
file里的内容被读进来,显示在与test匹配的行后面,若是匹配多行,则file的内容将显示在全部匹配行的下面:
sed '/test/r file' filename
复制代码
写入文件:w命令
在example中全部包含test的行都被写入file里:
sed -n '/test/w file' example
复制代码
追加(行下):a命令
将 this is a test line 追加到 以test 开头的行后面:
sed '/^test/a\this is a test line' jb.txt
复制代码
在 test.conf 文件第2行以后插入 this is a test line:
sed -i '2a\this is a test line' test.conf
复制代码
插入(行上):i命令
将 this is a test line 追加到以test开头的行前面:
sed '/^test/i\this is a test line' jb.txt
复制代码
在test.conf文件第5行以前插入this is a test line:
sed -i '5i\this is a test line' test.conf
复制代码
下一个:n命令
若是test被匹配,则移动到匹配行的下一行,替换这一行的aa,变为bb,并打印该行,而后继续:
sed '/test/{ n; s/aa/bb/; }' jb.txt
复制代码
变形:y命令
把1~10行内全部abcde转变为大写,注意,正则表达式元字符不能使用这个命令:
sed '1,10y/abcde/ABCDE/' jb.txt
复制代码
退出:q命令
打印完第10行后,退出sed
sed '10q' jb.txt
复制代码
保持和获取:h命令和G命令
在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,不然全部被处理的行都将 打印在屏幕上。
接着模式空间被清空,并存入新的一行等待处理。
sed -e '/test/h' -e '$G' jb.txt
复制代码
在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。
第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,而后把它放回模式空间中,且追加到如今已经存在于模式空间中的行的末尾。
在这个例子中就是追加到最后一行。
简单来讲,任何包含test的行都被复制并追加到该文件的末尾。
保持和互换:h命令和x命令
互换模式空间和保持缓冲区的内容。
也就是把包含test与check的行互换:
sed -e '/test/h' -e '/check/x' file
复制代码
脚本scriptfile
sed脚本是一个sed的命令清单,启动Sed时以-f选项引导脚本文件名。
Sed对于脚本中输入的命令很是挑剔,在命令的末尾不能有任何空白或文本,若是在一行中有多个命令,要用分号分隔。
以#
开头的行为注释行,且不能跨行。
sed [options] -f scriptfile file(s)
复制代码
打印奇数行或偶数行
方法1:
sed -n 'p;n' test.txt #奇数行
sed -n 'n;p' test.txt #偶数行
复制代码
方法2:
sed -n '1~2p' test.txt #奇数行
sed -n '2~2p' test.txt #偶数行
复制代码
打印匹配字符串的下一行
grep -A 1 SCC URFILE
sed -n '/SCC/{n;p}' URFILE
awk '/SCC/{getline; print}' URFILE
复制代码
总的来讲,sed 更适合编辑匹配到的文本;
xargs 是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
能够将输入内容(一般经过命令行管道传递),转成后续命令的参数,一般用途有:
之因此能用到这个命令,关键是因为不少命令不支持|管道来传递参数,而平常工做中有有这个必要,因此就有了 xargs 命令:
find /sbin -perm +700 |ls -l #这个命令是错误的
find /sbin -perm +700 |xargs ls -l #这样才是正确的
复制代码
xargs 通常是和管道一块儿使用;
somecommand |xargs -item command
复制代码
参数 | 说明 |
---|---|
-0 | 当 stdin 含有特殊子元的时候,将其当成通常字符; |
-a file | 从文件中读入做为sdtin; |
-e flag | flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就中止; |
-p | 当每次执行一个argument的时候询问一次用户; |
-n num | 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用全部的; |
-t | 表示先打印命令,而后再执行; |
-i 或-I | 将xargs的每项名称,通常是一行一行赋值给 {},能够用 {} 代替; |
-r no-run-if-empty | 当xargs的输入为空的时候则中止xargs,不用再去执行了; |
-s num | 命令行的最大字符数,指的是 xargs 后面那个命令的最大命令行字符数; |
-L num | 从标准输入一次读取 num 行送给 command 命令; |
-d delim | 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符; |
-x | exit的意思,主要是配合-s使用; |
-P | 修改最大的进程数,默认是1; |
定义一个测试文件,内有多行文本数据:
# cat test.txt
a b c d e f g
h i j k l m n
o p q
r s t
u v w x y z
复制代码
多行输入单行输出
# cat test.txt | xargs
---------------------------------------------------
a b c d e f g h i j k l m n o p q r s t u v w x y z
复制代码
-n 选项多行输出
# cat test.txt | xargs -n3
---------------------------------
a b c
d e f
g h i
j k l
m n o
p q r
s t u
v w x
y z
复制代码
-d 选项能够自定义一个定界符
# echo "nameXnameXnameXname" | xargs -dX
------------------------------------------
name name name name
复制代码
结合 -n 选项使用
# echo "nameXnameXnameXname" | xargs -dX -n2
------------------------------------------
name name
name name
复制代码
读取 stdin,将格式化后的参数传递给命令; 假设一个命令为 sk.sh 和一个保存参数的文件 arg.txt:
#!/bin/bash
#sk.sh命令内容,打印出全部参数。
echo $*
复制代码
arg.txt文件内容:
# cat arg.txt
------------------------------------------
aaa
bbb
ccc
复制代码
xargs 的一个选项 -I
,使用 -I
指定一个替换字符串 {}
,这个字符串在 xargs 扩展时会被替换掉,当 -I 与 xargs 结合使用,每个参数命令都会被执行一次:
# cat arg.txt | xargs -I {} ./sk.sh -p {} -l
-------------------------------------------
-p aaa -l
-p bbb -l
-p ccc -l
复制代码
复制全部图片文件到 /data/images 目录下
ls *.jpg | xargs -n1 -I cp {} /data/images
复制代码
xargs 结合 find 使用
用 rm 删除太多的文件时候,可能获得一个错误信息:/bin/rm Argument list too long. 用 xargs 去避免这个问题:
find . -type f -name "*.log" -print0 | xargs -0 rm -f
复制代码
xargs -0 将 \0 做为定界符; 统计一个源代码目录中全部 php 文件的行数
find . -type f -name "*.php" -print0 | xargs -0 wc -l
复制代码
查找全部的 jpg 文件,而且压缩它们
find . -type f -name "*.jpg" -print | xargs tar -czvf images.tar.gz
复制代码
xargs 其余应用
假如你有一个文件包含了不少你但愿下载的 URL,你可以使用 xargs下载全部连接:
# cat url-list.txt | xargs wget -c
复制代码
curl命令是个功能强大的网络工具,支持经过http、ftp等方式下载文件、上传文件。
还能够用来抓取网页、网络监控等方面的开发,解决开发过程当中遇到的问题。
curl命令参数不少,这里只列出曾经用过、特别是在shell脚本中用到过的那些。
参数 | 说明 |
---|---|
-v/--verbose | 小写的v参数,用于打印更多信息,包括发送的请求信息,这在调试脚本是特别有用; |
-m/--max-time | 指定处理的最大时长; |
-H/--header
|
指定请求头参数; |
-s/--slient | 减小输出的信息,好比进度; |
--connect-timeout | 指定尝试链接的最大时长; |
-x/--proxy <proxyhost[:port]> | 指定代理服务器地址和端口,端口默认为1080; |
-T/--upload-file | 指定上传文件路径; |
-o/--output | 指定输出文件名称; |
-d/--data/--data-ascii | 指定POST的内容; |
--retry | 指定重试次数; |
-e/--referer | 指定引用地址; |
-I/--head | 仅返回头部信息,使用HEAD请求; |
curl安装
sudo apt-get install curl
复制代码
GET请求
curl http://www.baidu.com
#回车以后,HTML内容打印在屏幕上;
#若是这里的URL指向的是一个文件或者一幅图均可以直接下载到本地;
curl -i "http://www.baidu.com"
#显示所有信息
curl -l "http://www.baidu.com"
#只显示头部信息
curl -v "http://www.baidu.com"
#显示get请求全过程解析
复制代码
下载
保存网页:
curl -o baidu.html http://www.baidu.com
复制代码
下载一个图片
curl -o girl.jpg http://hostname.com/girl.jpg
复制代码
若是想下载图片的名字和服务器保持一致 -O
大写的O
curl -O http://hostname.com/girl.jpg
复制代码
能够看到屏幕上出现一个下载页面进度指示,等到100%,就保存完成了.
上传
-T/--upload-file:往服务器上传文件
复制代码
用法:
#上传多个文件
curl -T "img[1-1000].png" ftp://example.com/upload/
#上传多个文件
curl -T "{file1,file2}" http://www.example.com
复制代码
GET请求
带参:
curl http://www.xxxx.com/getDataList?param1=value1¶m2=value2
复制代码
POST方法
-d或--data参数
:
post请求,用法:
curl -d "id=1&name=test" http://example.com/example.php
#需把请求的参数和URL分开
复制代码
同时可使用:
curl -d "id=1" -d "name=test" http://example.com/example.php
#至关于提交了两个参数。
复制代码
也能够指定一个文件,将该文件中的内容看成数据传递给服务器端
curl --data @filename https://hostname.com/xxx
复制代码
当提交的参数值中有特殊字符就须要先转义。
如空格时,就须要转义成%20。
curl -d "value%201" http://hostname.com
复制代码
--data-urlencode参数
:
能够自动转义成特殊字符,无需人工事先转义。
curl --data-urlencode "name=April 1" http://example.com/example.php
复制代码
-F或--form
:
将本地文件上传到服务器,用法为:
curl -F "filename=@/home/test/test.pic" http://example.com/example.php
#千万不能漏掉@符号。
复制代码
设置referer
有时候咱们若是直接请求某个URL不能成功,它须要判断referer是否正确,那就能够经过-e或--referer参数模拟
curl --referer http://www.example.com http://www.example.com
复制代码
指定User Agent
-A/--user-agent
:
假装成指定的浏览器Chrome访问
用法:
curl -A "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" www.baidu.com
复制代码
伪造cookie
-b或--cookie
:
有两种用法,一是指定参数和值:
curl --cookie "name=xxx" http://www.example.com 二是从文件读取:
curl -b /cookie.txt http://www.example.com
复制代码
保存cookie
-c/--cookie-jar
:
curl命令执行后保存操做时生成的cookie到文件:
curl -c ./cookie.txt -d username=aaaa -d pwd=****** http://www.example.com
复制代码
将网站的cookies信息保存到sugarcookies文件中
curl -D cookies.txt http://localhost/sugarcrm/index.php
复制代码
定义输出显示内容
-w/--write-out
:
能够定义输出的内容,如经常使用的http码,tcp链接时间,域名解析的时间,握手时间及第一时间响应时间等,很是强大。
一、打印出返回的http码
curl -o /dev/null -s -w %{http_code} "http://www.baidu.com"
复制代码
二、打印响应时间
curl -o /dev/null -s -w "time_total: %{time_total}\n" "http://www.baidu.com"
复制代码
CURL受权
在访问须要受权的页面时,可经过-u选项提供用户名和密码进行受权
curl -u username:password URL
复制代码
一般的作法是在命令行只输入用户名,以后会提示输入密码,这样能够保证在查看历史记录时不会将密码泄露
curl -u username URL
复制代码
#!/bin/bash
function httpRequest()
{
#curl 请求
info=`curl -s -m 10 --connect-timeout 10 -I $1`
#获取返回码
code=`echo $info|grep "HTTP"|awk '{print $2}'`
#对响应码进行判断
if [ "$code" == "200" ];then
echo "请求成功,响应码是$code"
else
echo "请求失败,响应码是$code"
fi
}
httpRequest "$1"
复制代码
执行结果:
呼,终于搞定了,不容易,但愿能帮助你快速了解shell;
本章从什么是shell开始,讲解变量、注释、字符串及操做、数组、传参、管道、条件/流程判断、以及经常使用的ps\grep\sed等命令简单介绍;
目的只是但愿能快速了解shell,否则懵逼半天,简单看完后留个大概印象,好歹再次见面就知道什么了;
最后,谢谢你们~