Unix Shell Tips
查看系统当中合法的shell
cat /etc/shells
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/ksh
/bin/rksh
[root@localhost ~]#
修改用户登录时使用的shell程序
useradd lin
chsh -s /bin/sh lin
grep lin /etc/passwd
测试:
[root@localhost ~]# useradd lin
[root@localhost ~]# chsh -s /bin/sh lin
Changing shell for lin.
Shell changed.
[root@localhost ~]# grep lin /etc/passwd
lin:x:54322:54331::/home/lin:/bin/sh
[root@localhost ~]#
用户的登录流程
所有用户:
/etc/profile
/etc/profile.d/*
当前用户的 ~/.bash_profile ~/.bashrc /etc/bashrc (所有用户)
流程如下:
/etc/profile start
/etc/profile end
~/.bash_profile start
~/.bashrc start
/etc/bashrc start
/etc/bashrc end
~/.bashrc end
~/.bash_profile end
变量的设置、查看和取消 echo unset
[lin@localhost ~]$ echo $test01
[lin@localhost ~]$ test01=echotest
[lin@localhost ~]$ echo $test01
echotest
[lin@localhost ~]$ unset test01
[lin@localhost ~]$ echo $test01
[lin@localhost ~]$
变量设定方式
变量设定方式 | 说明 |
${变量#关键词} | 若变量内容从头开始的数据符合『关键词』,则将符合的最短数据删除 |
${变量##关键词} | 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据删除 |
${变量%关键词} | 若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据删除 |
${变量%%关键词} | 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据删除 |
${变量/旧字符串/新字符串} | 若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串替换』 |
${变量//旧字符串/新字符串} | 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串替换』 |
[lin@localhost ~]$ path=${PATH}
[lin@localhost ~]$ echo $path
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin
[lin@localhost ~]$ path=/first/bin:${path}:/last/bin
[lin@localhost ~]$ echo $path
/first/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin:/last/bin
[lin@localhost ~]$
[lin@localhost ~]$ echo ${path#/first/bin:}
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin:/last/bin
[lin@localhost ~]$ echo ${path#/*/bin:}
/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin:/last/bin
[lin@localhost ~]$ echo ${path##/*/bin:}
/last/bin
[lin@localhost ~]$
[lin@localhost ~]$ echo ${path%:/last/bin}
/first/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin
[lin@localhost ~]$ echo ${path%%:/*/bin}
/first/bin
[lin@localhost ~]$
[lin@localhost ~]$ echo ${path/bin/BIN}
/first/BIN:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/lin/.local/bin:/home/lin/bin:/last/bin
[lin@localhost ~]$ echo ${path//bin/BIN}
/first/BIN:/usr/local/BIN:/BIN:/usr/BIN:/usr/local/sBIN:/usr/sBIN:/home/lin/.local/BIN:/home/lin/BIN:/last/BIN
[lin@localhost ~]$
变量
env | 列出目前shell环境下的所有全局变量 |
set | 查看所有变量,包括环境变量和局部变量 |
read 从键盘读取数据存入变量
read -p "plz input yourname:" -t 30 name 按下回车输入变量name的值,会等待30s结束
数组
array
数组的设定
A[0]=1;A[1]=2;A[2]=3
A=(1 2 3)
A=(1 2 3 [50]=4)
A=(1 2 3 [50]=4 5)
数组的读取
echo ${A[0]}
echo ${A[@]}
echo ${A[*]}
-
代表的是一次取出所有的值 ,@ 代表依次取值
for i in “${A[@]}”;do echo $i;done for i in “${A[*]}”;do echo $i;done
测试:
[lin@localhost ~]$ A[0]=1;A[1]=2;A[2]=3
[lin@localhost ~]$ echo ${A[0]}
1
[lin@localhost ~]$ echo ${A[4]}
[lin@localhost ~]$ echo ${A[@]}
1 2 3
[lin@localhost ~]$ echo ${A[*]}
1 2 3
[lin@localhost ~]$
[lin@localhost ~]$ for i in "${A[@]}";do echo $i;done
1
2
3
[lin@localhost ~]$ for i in "${A[*]}";do echo $i;done
1 2 3
[lin@localhost ~]$
declare declare 参数 -a 将变量看成数组 -i 将变量看成整数 -r 使变量只读 x=1 y=2 sum=$(($x+$y))
重定向
用法总结
1> :以覆盖的方法将『正确的数据』输出到指定的文件中;
1>>:以追加的方法将『正确的数据』输出到指定的文件中;
2> :以覆盖的方法将『错误的数据』输出到指定的文件中;
2>>:以追加的方法将『错误的数据』输出到指定的文件中;
cat 从键盘读取数据存入文件
cat > /tmp/catfile 以ctrl+d结束
cat > /tmp/catfile < /tmp/passwd
cat > /tmp/catfile << ENDF
standard in
ENDF===>结束提示符
命令执行的判断依据
CMD1 && CMD2 如果前一个命令 (CMD1) 能够正确被执行 , 则执行后一个命令 (CMD2) CMD1 || CMD2 如果前一个命令 (CMD1) 被正确执行 , 则不执行后一个命令 (CMD2), 如果前一个命令(CMD1) 执行错误 , 则执行后一个命令 (CMD2). CMD1 ; CMD2 命令之间没有关系,从第一个开始执行,不管是否正确执行都会去执行第二个命令
管道
#截取 grep cut
[lin@localhost ~]$ head /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[lin@localhost ~]$ head /etc/passwd | cut -d : -f 3
0
1
2
3
4
5
6
7
8
11
[lin@localhost ~]$ head /etc/passwd | grep bash$
root:x:0:0:root:/root:/bin/bash
[lin@localhost ~]$
#排序 sort uniq
[lin@localhost ~]$ head /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[lin@localhost ~]$ head /etc/passwd | sort -t: -k3 -n
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
[lin@localhost ~]$ head /etc/passwd | sort -t: -k4 -n
halt:x:7:0:halt:/sbin:/sbin/halt
operator:x:11:0:operator:/root:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
sync:x:5:0:sync:/sbin:/bin/sync
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
[lin@localhost ~]$
#统计 wc
[lin@localhost ~]$ wc -l /etc/passwd
25 /etc/passwd
[lin@localhost ~]$
shell 脚本
1> 魔法字符 “ #! ”: 出现在脚本第一行 , 用于定义命令解释器。
2> “ # ” 号开头的行 : 除了第一行的魔法字符以外 , 其他以 ” # “ 号开头 的行是注示。这些行不会被运行 , 只是给人阅读使用。
3> 系统命令 :shell 脚本中运行解释的系统命令。
4> 变量 : 脚本运行过程中某些反复调用的值的暂存地。
5> 流程控制语句 : 判断 , 循环 , 跳转等流程控制。
6> bash 脚本名称 bash -x 以调试模式来运行脚本
7> ./ 脚本名称 --> 需要对脚本有可执行的权限
判断条件
test 判断 man test 查看的相关的判断指令
数字的判断-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
-ne 不等于
-eq 等于
字符的判断
-z 空
= 字符相等
!= 字符不相等
-n 非空
-a 逻辑与
-o 逻辑或
文件的判断
-d 文件是不是一个目录
-f 是不是一个普通文件
-e 文件是不是存在
注意 :
- 括号两边有空格
-
判断符号两边有空格
[lin@localhost ~]$ test 6 -gt 9 [lin@localhost ~]$ echo $? 1 [lin@localhost ~]$ test 6 -gt 5 [lin@localhost ~]$ echo $? 0 [lin@localhost ~]$
if 语法格式
if condition -->condition 指的是判断的条件
then
CMD1 --> CMD1 指的是满足判断条件后执行的语句
else
CMD2 --> CMD2 指的是不满足判断条件执行的语句 then
fi
if condition
then
CMD1
elif condition
CMD2
else
CMD3
fi
for 语法格式
for 变量 in 取值范围
do
CMD
done
for i in {1..4}
do
n=0
while [ "$n" -lt "$i" ]
do
echo -n " "
n=`expr $n + 1`
done
echo *
done
count=10
for i in `seq 1 $count`
do
for j in `seq 1 $(($i-1))`
do
echo -n ' '
done
echo '*'
done
[lin@localhost ~]$ count=10
[lin@localhost ~]$ for i in `seq 1 $count`
> do
> for j in `seq 1 $(($i-1))`
> do
> echo -n ' '
> done
> echo '*'
> done
*
*
*
*
*
*
*
*
*
*
[lin@localhost ~]$
for i in `seq 1 9`
do
for j in `seq 1 $i`
do
echo -n "$i*$j=$(($i*$j)) "
done
echo
done
[lin@localhost ~]$ for i in `seq 1 9`
> do
> for j in `seq 1 $i`
> do
> echo -n "$i*$j=$(($i*$j)) "
> done
> echo
> done
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
[lin@localhost ~]$
while 语法格式
while condition 指的是判断的条件
do
CMD
done
数字的判断
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
-ne 不等于
-eq 等于
字符的判断 -z 空 = 字符相等 != 字符不相等 -n 非空 -a 逻辑与 -o 逻辑或
文件的判断 -d 文件是不是一个目录 -f 是不是一个普通文件 -e 文件是不是存在
until 语法格式
until condition –> 不满足 condition, 则执行 cmd
do
CMD
done
####
[lin@localhost ~]$ cat cmd.sh
#!/bin/bash
SLEEP()
{
sleep $1
}
DIR()
{
ls -ld $1
ls -l $1
}
RM()
{
rm -rf $1
}
case $1 in
-t)
SLEEP $2;;
-l)
DIR $2;;
-r)
RM $2;;
--help)
echo "Usage: ls [-t|-l|-r] name";;
*)
echo "Usage: ls [-t|-l|-r] name";;
esac
[lin@localhost ~]$
正则表达式
特殊字符 代表意义
[:alnum:] | 代表英文大小写字符及数字 ,0-9, A-Z, a-z
[:alpha:] | 代表任何英文大小写字符 , A-Z, a-z
[:lower:] | 代表小写字符 , a-z
[:upper:] | 代表大写字符 ,A-Z
[:digit:] | 代表数字而已 , 0-9
[:xdigit:] | 代表 16 进制数字 , 因此包括 : 0-9, A-F, a-f
[:blank:] | 代表空格键和 [Tab] 按键
[:space:] | 任何会产生空白的字符,包括空格键 , [Tab], CR 等等
[:graph:] | 除了空格键 ( 空格键和 [Tab] ) 外的其他所有按键
[:cntrl:] | 代表键盘上面的控制按键 , 包括 CR, LF, Tab, Del.. 等等
[:print:] | 代表任何可以被打印出来的字符
[:punct:] | 代表标点符号 (punctuation symbol) :" ' ? ! ; : # $...
非打印字符 非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列:
字符 描述
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK
常见的正则表达式
^ 行首定位符
$ 行尾定位符
. 匹配除换行符之外的单个字符
* 匹配 0 个或多个前一字符
? 匹配 0 个或1个前一字符
+ 匹配 1 个或多个前一个字符
[ ] 匹配指定字符组内的任一字符
[^] 匹配不在指定字符组内的任一字符
\< 单词起始边界匹配符
\> 单词结束边界匹配符
x\{m\} 连续 M 个字符 X
x\{m,\} 至少 M 个字符 X
x\{m,n\}至少 M 个最多 N 个字符 X
a开头字符串
[lin@localhost ~]$ cat co.sh
#!/bin/bash
if [[ $1 =~ ^a ]]
then
echo OK
else
echo NG
fi
[lin@localhost ~]$ ./co.sh aa
OK
[lin@localhost ~]$ ./co.sh ab
OK
[lin@localhost ~]$ ./co.sh ba
NG
[lin@localhost ~]$
if判断匹配ip地址
#!/bin/bash
if [[ $1 =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]
then
IP=(${1//\./ })
[ ${IP[0]} -gt 0 -a ${IP[0]} -lt 255 ] && [ ${IP[1]} -ge 0 -a ${IP[1]} -lt 255 ] && [ ${IP[2]} -ge 0 -a ${IP[2]} -lt 255 ] && [ ${IP[3]} -gt 0 -a ${IP[3]} -lt 255 ] && echo ok || echo no
else
echo "this is not IPADDR!"
fi
sed/awk
sed命令的原理
读文件---一行一行读
存入缓存空间
匹配行---是---动作--继续读取
---不是------ 继续读取
读到最后一行为止
输出
sed命令的用法
sed [-options] '[cmd]' filename
sed [-options] '[哪些行][干什么]' filename
下载mysqlbinlog.row文件
*打印第三行
*打印1到5行
*打印最后一行
*打印30到最后一行
*打印包含“BEGIN”的行
*打印包含“COMMIT”的行
*打印以“###”开头的行
*删除每一行的“### ”
*删除所有“/到/”
*将“DELETE FROM”替换为“insert into”
*将“INSERT INTO”替换为“delete from”
*将“SET”替换为“where”
*将“WHERE”替换为“set”
*将“@1”替换为“id”
*将“@2”替换为“name”
[root@mysqlhost ~]# sed '3p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '3p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '1,5p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '$p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '30,$p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '/BEGIN/p' mysqlbinlog.row
[root@mysqlhost ~]# sed -n '/COMMIT/p' mysqlbinlog.row
[root@mysqlhost ~]# sed '{s/### //;s@\/\*.*\*\/@@;s/DELETE FROM/insert into/;s/INSERT INTO/delete from/;s/SET/where/;s/WHERE/set/;s/@1/id/;s/@2/name/}' mysqlbinlog.row
调用awk
有三种方式调用awk
- 命令行方式 awk [-F field-separator] ‘commands’ input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
- shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
- 将所有的awk命令插入一个单独文件,然后调用: awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
显示最近登录的5个帐号
[lin@localhost ~]$ last -n 5 | awk '{print $1}'
root
reboot
root
root
root
wtmp
[lin@localhost ~]$
显示账户和账户对应的shell,而账户与shell之间以tab键分割
[lin@localhost ~]$ head /etc/passwd | awk -F ':' '{print $1"\t"$7}'
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
mail /sbin/nologin
operator /sbin/nologin
[lin@localhost ~]$
awk工作流程是这样的:
先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
[lin@localhost ~]$ head /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "last,/bin/nosh"}'
name,shell
root,/bin/bash
bin,/sbin/nologin
daemon,/sbin/nologin
adm,/sbin/nologin
lp,/sbin/nologin
sync,/bin/sync
shutdown,/sbin/shutdown
halt,/sbin/halt
mail,/sbin/nologin
operator,/sbin/nologin
last,/bin/nosh
[lin@localhost ~]$
awk内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
[lin@localhost ~]$ awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd | head
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync
filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
filename:/etc/passwd,linenumber:8,columns:7,linecontent:halt:x:7:0:halt:/sbin:/sbin/halt
filename:/etc/passwd,linenumber:9,columns:7,linecontent:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
filename:/etc/passwd,linenumber:10,columns:7,linecontent:operator:x:11:0:operator:/root:/sbin/nologin
[lin@localhost ~]$
下面统计/etc/passwd的账户人数
awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd
统计某个文件夹下的文件占用的字节数
ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'
Have a good work&life! 2019/07 via LinHong