shell语法及常用法命令

执行脚本

#! /bin/sh
cd ..
ls

sh test.sh 或者 source test.sh
脚本文件加上可执行权限然后执行:
chmod a+x test.sh
./test.sh

命令执行

``或$()

$ echo `date`
2020年 02月 27日 星期四 19:37:25 CST
$ echo $(date)
2020年 02月 27日 星期四 19:37:40 CST

算术运算

$(())

$ echo $((11*11))
121

$[base#n],其中base表示进制,n按照base进制解释

$ echo $[10#121/11]
11

单引号与双引号

$ DATE=`date`
$ echo '$DATE'
$DATE
$ echo "$DATE"
2020年 02月 27日 星期四 19:45:32 CST

单引号里的内容会被认为是字符串,注意字符串中不能出现单引号,双引号中可以被通配符替换。

通配符

通配符作用
*匹配0个或多个任意字符
?匹配一个任意字符
[若干字符]匹配方括号中任意一个字符的一次出现
$ ls /dev/ttyS*
$ ls ch0?.doc
$ ls ch0[0-2].doc
$ ls ch[012]   [0-9].doc

条件测试

test与[ ]作用相同

$ test -d Desktop
$ echo $?
0

注意[ ] 命令与参数之间都要有空格

 [ -d /bin/bash ]
pi@qing:~/Pictures $ echo $?
1

值得注意的是,这里的Exit Status值与正常的逻辑值相反,Exit Status为0,则条件值为真,Exit Status为1,则条件值为假。

常用的条件测试说明
[ -d DIR ]如果DIR存在并且是一个目录则为真
[ -f FILE ]如果FILE存在且是一个普通文件则为真
[ -z STRING ]如果STRING的长度为零则为真
[ -n STRING ]如果STRING的长度非零则为真
[ STRING1 = STRING2 ]如果两个字符串相同则为真
[ STRING1 != STRING2 ]如果字符串不相同则为真
[ ARG1 OP ARG2 ]ARG1和ARG2应该是整数或者取值为整数的变量

OP可以为-eq(等于), -ne(不等于),-lt(小于),-le(小于等于),-gt(大于),-ge(大于等于)

STRING1 = STRING2注意两个字符串之间的空格,STRING1=STRING2代表赋值

逻辑判断

逻辑判断
[ ! EXPR ]!表示逻辑反
[ EXPR1 -a EXPR2 ]-a表示逻辑与
[ EXPR1 -o EXPR2 ]-o表示逻辑或

条件分支语句

if/then/elif/else/fi

再次注意一遍,if命令的参数组成一条子命令,如果该子命令的Exit Status为0(表示真),则执行then后面的子命令,如果Exit Status非0(表示假),则执行elif、else或者fi后面的子命令。这里的真假01和一般的逻辑判断相反。

#! /bin/sh
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
if [ "$YES_OR_NO" = "yes" ]; then
echo "Good morning!"
elif [ "$YES_OR_NO" = "no" ]; then
echo "Good afternoon!"
else
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
exit 1
fi
exit 0

此外,Shell还提供了&&和||语法,和C语言类似,具有Short-circuit特性,很多Shell脚本喜欢写成这样:

test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)

&&相当于“if…then…”,而||相当于“if not…then…”。&&和||用于连接两个命令,而上面讲的-a和-o仅用于在测试表达式中连接两个测试条件,要注意它们的区别,例如,

test "$VAR" -gt 1 -a "$VAR" -lt 3
test "$VAR" -gt 1 && test "$VAR" -lt 3

两种写法等价。

case

#! /bin/bash
echo 'Is it morming'
read YES_OR_NO
case YES_OR_NO in
  yes|YES|y)
    echo 'good morning';;
  n*)
    echo 'good aftenoon';;
  *)
    echo 'sorry';;
esac
exit 0

每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。

循环

for do done

#! /bin/bash
for VAR in dog cat rabbit; do
  echo "I like $VAR"
done

while do done

#! /bin/bash
echo 'ENTER the password'
NUM=1
while [ $NUM -le 5 ]; do
  read TRY
  if [ $TRY = "secret" ]; then
    echo 'login sucess'
    break
  else 
    NUM=$(($NUM+1))
    echo 'try again'
  fi
done
echo 'try too many'

break可以指定跳出几层循环,continue跳过本次循环步,没跳出整个循环。

位置参数和特殊变量

参数变量解释
$0相当于C语言main函数的argv[0],一般为运行名称
$1、$2…位置参数(Positional Parameter),按照传递顺序来
$#传参的个数
$@表示参数列表"$1" “$2” …,例如可以用在for循环中的in后面。
$*表示参数列表"$1" “$2” …,同上
$?上一条命令的Exit Status
$$当前进程号
$ cat < practice2
#! /bin/bash
echo "$#"
echo "$0"
echo "$1"
echo "$2"
echo "$3"
echo "$@"

$ source practice2 aa bb
2
-bash
aa
bb

aa bb

常用基本命令

echo

echo [option] string
-e 解析转义字符
-n 不回车换行。默认情况echo回显的内容后面跟一个回车换行。

$ echo -e 'hello\n\n'
hello


$ echo  'hello\n\n'
hello\n\n
$ echo -n 'hello\n\n'
hello\n\n$ 

管道|

可以通过管道把一个命令的输出传递给另一个命令做输入。管道用竖线表示。

tee

tee命令把结果输出到标准输出,另一个副本输出到相应文件。

[qing@qing hangbao]$ df -h | sort -n
devtmpfs        990M     0  990M   0% /dev
/dev/vda1        40G  3.4G   35G   9% /
Filesystem      Size  Used Avail Use% Mounted on
tmpfs          1000M     0 1000M   0% /dev/shm
tmpfs          1000M     0 1000M   0% /sys/fs/cgroup
tmpfs          1000M  113M  887M  12% /run
tmpfs           200M     0  200M   0% /run/user/0
tmpfs           200M     0  200M   0% /run/user/1000

文件重定向

cmd
cmd > file把标准输出重定向到新文件中
cmd >> file追加
cmd > file 2>&1标准出错也重定向到1所指向的file里
cmd >> file 2>&1
cmd < file1 > file2输入输出都定向到文件里
cmd < &fd把文件描述符fd作为标准输入
cmd > &fd把文件描述符fd作为标准输出
cmd < &-关闭标准输入
nohup sh test.sh >test.log 2>&1 &

函数

#! /bin/sh
foo(){ echo "Function foo is called";}
echo "-=start=-"
foo
echo "-=end=-"

注意函数体的左花括号’{‘和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号’}'写在同一行,命令末尾必须有;号。

#! /bin/bash
is_directory()
{
  if [ -d $1 ]; then
    return 0
  else 
   return 1
  fi
}

for DIR in $@; do
  if is_directory $DIR; then
    echo "$DIR is exiting"
  else 
    echo 'Creating now'
    mkdir $DIR > /dev/null 2>&1
    if [ $? -eq 0 ]; then 
       echo "create $DIR success"
    else 
       echo "create $DIR failure"
    fi
  fi
done 
在这里插入代码片

Shell脚本的调试方法

-n读一遍脚本中的命令但不执行,用于检查脚本中的语法错误
-v一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
-x提供跟踪执行信息,将执行的每一条命令和结果依次打印出来

使用这些选项有三种方法,一是在命令行提供参数

sh -x ./script.sh

二是在脚本开头提供参数

    #! /bin/sh -x

第三种方法是在脚本中用set命令启用或禁用参数

#! /bin/sh
if [ -z "$1" ]; then
set -x
  echo "ERROR: Insufficient Args."
  exit 1
set +x
fi

set -x和set +x分别表示启用和禁用-x参数,这样可以只对脚本中的某一段进行跟踪调试。

常用命令

find

一般格式

find pathname -options [-print -exec -ok ...]
-options解释
-name按照文件名查找文件。
-perm按照文件权限来查找文件。
-prune使用这一选项可以使find命令不在当前指定的目录中查找,如果同时使用-depth选项,那么-prune将被find命令忽略。
-user按照文件属主来查找文件。
-group按照文件所属的组来查找文件。
-mtime -n +n按照文件的更改时间来查找文件,-n表示文件更改时间距现在n天以内,+n表示文件更改时间距现在n天以前。find命令还有-atime和-ctime 选项,但它们都和-m time选项。
-nogroup查找无有效所属组的文件,即该文件所属的组在/etc/groups中不存在。
-nouser查找无有效属主的文件,即该文件的属主在/etc/passwd中不存在。
-newer file1 ! file2查找更改时间比文件file1新但比文件file2旧的文件。
-type查找某一类型的文件, b - 块设备文件。 d - 目录。 c - 字符设备文件。 p - 管道文件。 l - 符号链接文件。f - 普通文件。
-size n:[c]查找文件长度为n块的文件,带有c时表示文件长度以字节计。
-depth在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
-fstype查找位于某一类型文件系统中的文件,这些文件系统类型通常可以在配置文件/etc/fstab中找到,该配置文件中包含了本系统中有关文件系统的信息。
-mount在查找文件时不跨越文件系统mount点。
-follow如果find命令遇到符号链接文件,就跟踪至链接所指向的文件
mtime扩展
-amin n查找系统中最后N分钟访问的文件
-atimen 查找系统中最后n*24小时访问的文件
-cmin n查找系统中最后N分钟被改变文件状态的文件
-ctime n查找系统中最后n*24小时被改变文件状态的文件
-mmin n查找系统中最后N分钟被改变文件数据的文件
-mtime n查找系统中最后n*24小时被改变文件数据的文件
可选参数
-exec:find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为’command’ {} \;
-ok:和-exec的作用相同,只不过以一种更为安全的模式来执行该参数所给出的shell命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。

示例:
1,-name

find ~ -name "*.sh" -print

2,在/var/log目录中查找更改时间在5日以前的文件并删除它们

find /var/log -name "messages-*" -mtime +5 -ok rm {} \;

注意空格和分号

3,在当前目录下查找文件权限位为755的文件,即文件属主可以读、写、执行,其他用户可以读、执行的文件

find . -perm 755 -print

4,按文件属主查找文件

find ~ -user qing -print

5,为了查找系统中所有文件长度为0的普通文件,并列出它们的完整路径;

$ find / -type f -size 0 -exec ls -l {} \;

按照文件长度来查找文件,这里所指的文件长度既可以用块(block)来计量,也可以用字节来计量。以字节计量文件长度的表达形式为N c;以块计量文件长度只用数字表示即可。

xargs
在使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行。这里的exec的命令是一次性执行,当数量过大时,可能会出现内存溢出。

find . -type f -print | xargs file

用grep命令在所有的普通文件中搜索echo这个词

find . -type f -print | xargs grep "echo"
find . -name \* -type f -print | xargs grep "is" -n

grep

grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

-options
-c:只输出匹配行的计数。
-i:不区分大小写。
-h:查询多文件时不显示文件名。
-l:查询多文件时只输出包含匹配字符的文件名。
-n:显示匹配行及 行号。
-s:不显示不存在或无匹配文本的错误信息。
-v:显示不包含匹配文本的所有行。
–color=auto :可以将找到的关键词部分加上颜色的显示。
pattern正则表达式主要参数:
\:忽略正则表达式中特殊字符的原有含义。
^:匹配正则表达式的开始行。
$:匹配正则表达式的结束行。
<:从匹配正则表达 式的行开始。
>:到匹配正则表达式的行结束。
[ ]:单个字符,如[A]即A符合要求 。
[ - ]:范围,如[A-Z],即A、B、C一直到Z都符合要求 。

grep -E 与re正则表达式方法基本相同,可参考下面链接。
字符类

字符含义举例
字符含义举例
.匹配任意一个字符abc.可以匹配abcd、abc9等
[ ]匹配括号中的任意一个字符[abc]d可以匹配ad、bd或cd
-在[]括号内表示字符范围[0-9a-fA-F]可以匹配一位十六进制数字
^位于[]括号内的开头,匹配除括号中的字符之外的任意一个字符[^xy]匹配除xy之外的任一字符,因此[^xy]1可以匹配a1、b1但不匹配x1、y1

数量限定符

字符含义举例
?紧跟在它前面的单元应匹配零次或一次[0-9]?.[0-9]匹配0.0、2.3、.5等,由于.在正则表达式中是一个特殊字符,所以需要用\转义一下,取字面值
+紧跟在它前面的单元应匹配一次或多次[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+.[a-zA-Z0-9_.-]+匹配email地址
*紧跟在它前面的单元应匹配零次或多次[0-9][0-9]*匹配至少一位数字,等价于[0-9]+
{N}紧跟在它前面的单元应精确匹配N次[1-9][0-9]{2}匹配从100到999的整数
{N,}紧跟在它前面的单元应匹配至少N次[1-9][0-9]{2,}匹配三位以上(含三位)的整数
{,M}紧跟在它前面的单元应匹配最多M次[0-9]{,1}相当于[0-9]?
{N,M}紧跟在它前面的单元应匹配至少N次,最多M次[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}匹配IP地址

位置限定符

字符含义举例
^匹配行首的位置^Content匹配位于一行开头的Content
$匹配行末的位置;$匹配位于一行结尾的;号,^$匹配空行
<匹配单词开头的位置\<th匹配… this,但不匹配ethernet、tenth
\>匹配单词结尾的位置p>匹配leap …,但不匹配parent、sleepy
\b匹配单词开头或结尾的位置\bat\b匹配… at …,但不匹配cat、atexit、batch
\B匹配非单词开头和结尾的位置\Bat\B匹配battery,但不匹配… attend、hat …

grep -E 与re正则表达式方法基本相同,可参考下面链接。python中的正则表达式

sed

sed命令行的基本格式为

sed option 'script' file1 file2 ...
sed option -f scriptfile file1 file2 ...
常用选项含义:
–version显示sed版本。
–help显示帮助文档。
-n,–quiet,–silent静默输出,默认情况下,sed程序在所有的脚本指令执行完毕后,将自动打印模式空间中的内容,这些选项可以屏蔽自动打印。
-e script允许多个脚本指令被执行。
-f script-file, --file=script-file从文件中读取脚本指令,对编写自动脚本程序来说很棒!
-i,–in-place直接修改源文件,经过脚本指令处理后的内容将被输出至源文件(源文件被修改)慎用!
-r, --regexp-extended在脚本指令中使用扩展正则表达式
-s, --separate默认情况下,sed将把命令行指定的多个文件名作为一个长的连续的输入流。而GNU sed则允许把他们当作单独的文件,这样如正则表达式则不进行跨文件匹配。

对与直接修改源文件,不建议这样做,可以利用tee创建副本。
sed ‘s/love/too’ | tee a.txt

简单运用
a,append 追加
i,insert 插入
d,delete 删除
s,substitution 替换

/pattern/p  打印匹配pattern的行
/pattern/d  删除匹配pattern的行

1, 在输出testfile内容的第二行后添加"love"

sed "2a itcast" testfile

2,删除2,5行

 sed "2,5d" testfile

3,打印其中包含abc的行

sed '/abc/p' testfile

注意,sed是把待处理文件的内容连同处理结果一起输出到标准输出的,因此p命令表示除了把文件内容打印出来之外还额外打印一遍匹配pattern的行。

可以用-n来禁止输出,相当于grep

sed -n '/abc/p' testfile

替换的常见用法

sed /pattern/s/pattern1/pattern2/
#查找符合pattern的行,将该行第一个匹配pattern1的字符串替换为pattern2
sed /pattern/s/pattern1/pattern2/g  
#查找符合pattern的行,将该行所有匹配pattern1的字符串替换为pattern2

1,

$ cat testfile 
123
abc
456
$ sed 's/abc/~&~/' testfile 
123
~abc~
456

pattern2中的&表示原文件的当前行中与pattern1相匹配的字符串

2,

[qing@qing hangbao]$ sed -r 's/([0-9]).([0-9])/~\1~\2~/' testfile 
~1~3~
abc
~4~6~

pattern2中的\1表示与pattern1的第一个()括号相匹配的内容,\2表示与pattern1的第二个()括号相匹配的内容。

3,去掉所有的HTML标签

$ cat testfile 
<html><head><title>Hello World</title></head>
<body>Welcome to the world of regexp!</body></html>
$ sed -r 's/<[^>]+>//g' testfile 
Hello World
Welcome to the world of regexp!

4,

 sed   -r  '/[a-z0-9-]{36}/s/[a-z0-9-]{35}[a-z0-9]/love/g' testfile 

awk

sed以行为单位处理文件,awk比sed强的地方在于不仅能以行为单位还能以列为单位处理文件。awk缺省的行分隔符是换行,缺省的列分隔符是连续的空格和Tab,但是行分隔符和列分隔符都可以自定义,
命令的基本形式

awk option 'script' file1 file2 ...
awk option -f scriptfile file1 file2 ...

常见用法

/pattern/{actions}
condition{actions}

和sed类似,pattern是正则表达式,actions是一系列操作。awk程序一行一行读出待处理文件,如果某一行与pattern匹配,或者满足condition条件,则执行相应的actions,如果一条awk命令只有actions部分,则actions作用于待处理文件的每一行。

1,打印第二列

awk '{print $2;}' testfile

2,如果某种产品的库存量低于75则在行末标注需要订货

$ cat testfile
ProductA  30
ProductB  76
ProductC  55
$ awk '$2<75 {printf "%s\t%s\n" ,$0, "order";} $2>=75 {printf "%s\n" ,$0;}' testfile 
ProductA  30	order
ProductB  76
ProductC  55	order

3,统计一个文件中的空行数

$ awk '/^ *$/ {x=X+1} END {print x};' practice2 
1

awk常用的内建变量

变量名
FILENAME当前输入文件的文件名,该变量是只读的
NR当前行的行号,该变量是只读的,R代表record
NF当前行所拥有的列数,该变量是只读的,F代表field
OFS输出格式的列分隔符,缺省是空格
FS输入文件的列分融符,缺省是连续的空格和Tab
ORS输出格式的行分隔符,缺省是换行符
RS输入文件的行分隔符,缺省是换行符

1,打印系统中的用户帐号列表

awk 'BEGIN {FS=":"} {print $1;}' /etc/passwd

2,

nova list | awk 'BEGIN {FS="|"} {print $3}'

习题

  1. 求2个数之和
  2. 计算1-100的和
#! /bin/bash
x=1
R=0
while [ $x -le 100 ]; do
  R=$(($x+$R))
  x=$(($x+1))
done
echo "$R"
exit 0
  1. 将一目录下所有的文件的扩展名改为bak
  2. 编译当前目录下的所有.c文件
#! /bin/bash
for file in *.c;do echo %file ; gcc -o $(basename $file .c) $file ; sleep 2; done \
> compile 2>&1
  1. 打印root可以使用可执行文件数,处理结果: root’s bins: 2306
echo "root'a bins:`find /root -user root | xargs ls -l | sed '/-..x/p' | wc -l `"

这里指的是/root下拥有执行权限的文件

  1. 打印当前sshd的端口和进程id,处理结果: sshd Port&&pid: 22 5412
 netstat -apn | grep sshd | sed -n  -r 's/.*:::([0-9]+).*([0-9]+)\/sshd/\1 \2/p'
  1. 输出本机创建20000个目录所用的时间,处理结果:
#! /bin/bash 
time(
for i in {1..20000}; do 
  mkdir temp/nn$i
done
)
  1. 打印本机的交换分区大小,处理结果: Swap:1024M
free -m | grep Swap | awk '{print $2}'
  1. 文本分析,取出/etc/password中shell出现的次数
    4 /bin/bash
    1 /bin/sync
    1 /sbin/halt
    31 /sbin/nologin
    1 /sbin/shutdown
cat /etc/passwd | awk  -F: '$7!="" { print $7}' | sort | uniq -c
  1. 文件整理,employee文件中记录了工号和姓名,(提示join)
    employee.txt:
    100 Jason Smith
    200 John Doe
    300 Sanjay Gupta
    400 Ashok Sharma
    bonus文件中记录工号和工资
    bonus.txt:
    100 $5,000
    200 $500
    300 $3,000
    400 $1,250
    要求把两个文件合并并输出如下,处理结果:
    400 ashok sharma $1,250
    100 jason smith $5,000
    200 john doe $500
    300 sanjay gupta $3,000
 join employee.txt bonus.txt | sort -k 2
  1. 编写个shell脚本将当前目录下大于10K的文件转移到/tmp目录下
#! /bin/bash
for FILE in `ls -l | awk ' $5>10240 {print $9}'`; do
  mv $FILE /temp
done
ls -al /tmp
  1. 查看TCP连接状态
netstat -nat |awk '{print $6}' |sort|uniq -c|sort -rn
  1. 查找请求数请20个IP(常用于查找攻来源):
netstat -anlp|grep 80|grep tcp|awk '{print $5}' |awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20
  1. 获得访问前10位的ip地址
cat access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10

文本处理类的命令:

  • wc [option] [file]…
    -l: 统计行数
    -c: 统计字节数
    -w;统计单词数

  • tr: 转换字符或删除字符
    tr ‘集合1’ ‘集合2’
    tr -d ‘字符集合’

  • sort [option] file…
    -f: 忽略字符大小写;
    -n: 比较数值大小;
    -t: 指定分隔符
    -k: 指定分隔后进行比较字段
    -u: 重复的行,只显示一次;

  • uniq
    移除重复的行
    -c:显示每行重复的次数
    -d:仅显示重复过的行
    -u: 仅显示不曾重复的行

工具速查链接http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/index.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值