shell 编程
单引号、双引号、反引号、无引号
单引号:单引号被识别为普通字符串,就是不识别引号里面的特殊字符,属于强引用。
双引号:双引号里面的特殊字符是可以被识别的,是弱引用。
反引号:在linux中,反引号中的内容一般是一行或多行命令,当这些命令被反引号引着,命令执行结果就会以字符串的形式被保留下来。
无引号:如何是连续的符号可以不加引号,但是如果有空格就有歧义,最好使用双引号。
在unix系统中,程序会分析#!字符后面的内容,作为解释器的指令,比如: 以#!/bin/sh
开头的文件,程序在执行的时候会调用/bin/sh
,也就是bash解释器 以#!/usr/bin/python
开头的文件,就代表指定python解释器去执行。 如果没有指定shebang,脚本执行的时候就默认用shell去解释脚本。
yum install psmisc -y
pstree
文本处理
cut
sort
wc
sed > vi
awk
cut:显示切割的行数据 f:选择显示的列 s:不显示没有分隔符的行 d:自定义分隔符 sort:排序文件的行 n:按数值排序 r:倒序 t:自定义分隔符 k:选择排序列 u:合并相同行 f:忽略大小写
type:命令类型
外部命令 & 内部命令
help:内部命令帮助
help:内部命令清单,附带语法格式,描述
help 具体内部命令
man:帮助手册manual
yum install man man-pages -y
whereis : 定位命令位置
file:文件类型
echo:打印到标准输出
$PATH: 环境变量:路径
$LANG
/etc/profile 》 bash启动(交互方式)
变量:
a=3
echo $a
b=(1,2,3)
echo $b
b=(1 2 3)
echo $b
echo hello$agod
echo hello${a}god
echo ${b[2]}
- Filesystem Hierarchy Standard(文件系统层次化标准)
/boot
: 系统启动相关的文件,如内核、initrd,以及grub(bootloader)/dev
: 设备文件/etc
:配置文件/home
:用户的家目录,每一个用户的家目录通常默认为/home/USERNAME/root
:管理员的家目录;/lib
:库文件/media
:挂载点目录,移动设备/mnt
:挂载点目录,额外的临时文件系统/opt
:可选目录,第三方程序的安装目录/proc
:伪文件系统,内核映射文件/sys
:伪文件系统,跟硬件设备相关的属性映射文件/tmp
:临时文件,/var/tmp
/var
:可变化的文件/bin
: 可执行文件, 用户命令/sbin
:管理命令 df:显示磁盘使用情况 du:显示文件系统使用情况 ls:显示目录 cd:切换工作目录 pwd:显示当前工作目录 mkdir:创建目录 rm:删除 cp:拷贝 mv:移动 ln:链接 stat:元数据 touch
groupadd groupdel useradd userdel usermod id passwd sudo
su r w x 1 0 1
useradd sxt01 passwd sxt01 useradd sxt02 passwd sxt02
mkdir /var/swapdata
1,权限修正: chmod 770 swapdata | chmod o-rwx g+rwx swapdata 2,修正属组 groupadd sxtswap usermod -a -G sxtswap sxt01 usermod -a -G sxtswap sxt02 chown root:sxtswap swapdata chown :sxtswap ooxx.file chmod 770 ooxx.file id username
打开文件 vim /path/to/somefile vim +# :打开文件,并定位于第#行 vim +:打开文件,定位至最后一行 vim +/PATTERN : 打开文件,定位至第一次被PATTERN匹配到的行的行首 关闭文件 末行模式: :q 退出 没有动过文件 :wq 保存并退出 动过了,不后悔 :q! 不保存并退出 动过了,后悔了 :w 保存 :w! 强行保存 :wq --> :x
ZZ: 保存并退出 不需要冒号,编辑模式
sed:行编辑器
sed [options] 'AddressCommand' file ...
-n: 静默模式,不再默认显示模式空间中的内容 -i: 直接修改原文件 -e SCRIPT -e SCRIPT:可以同时执行多个脚本 -f /PATH/TO/SED_SCRIPT -r: 表示使用扩展正则表达式
sed:行编辑器Command d: 删除符合条件的行; p: 显示符合条件的行; a \string: 在指定的行后面追加新行,内容为string \n:可以用于换行 i \string: 在指定的行前面添加新行,内容为string r FILE: 将指定的文件的内容添加至符合条件的行处 w FILE: 将地址指定的范围内的行另存至指定的文件中; s/pattern/string/修饰符: 查找并替换,默认只替换每行中第一次被模式匹配到的字符串 g: 行内全局替换 i: 忽略字符大小写
s///: s###, s@@@
\(\), \1, \2
sed:行编辑器Address 可以没有 给定范围 查找指定行/str/
awk
$0
当前数据
$1
$2
awk是一个强大的文本分析工具。 相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。 简单来说awk就是把文件逐行的读入,(空格,制表符)为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk -F '{pattern + action}' {filenames}
- awk -F '自定义分隔符' ‘BEGIN{} 匿名{ fun } END{}’ 支持自定义分隔符 支持正则表达式匹配 支持自定义变量,数组 a[1] a[tom] map(key) 支持内置变量
变量 | 描述 |
---|---|
ARGC | 命令行参数个数 |
ARGV | 命令行参数排列 |
ENVIRON | 支持队列中系统环境变量的使用 |
FILENAME | awk浏览的文件名 |
FNR | 浏览文件的记录数 |
FS | 设置输入域分隔符,等价于命令行 -F选项 |
NF | 浏览记录的域的个数 |
NR | 已读的记录数 |
OFS | 输出域分隔符 |
ORS | 输出记录分隔符 |
RS | 控制记录分隔符 |
支持函数
print、split、substr、sub、gsub
支持流程控制语句,类C语言
if、while、do/while、for、break、continue
awk -F':' 'BEGIN{print "name,shell"} {print $1 "," $7} END{print "blue,/bin/nosh"}' passwd
#!/bin/bash
dict=$1
echo find path is ${dict}
oldIFS=$IFS
IFS=$'\n'
res=$( du -a $1 | sort -nr )
for i in $res; do
#filename=`awk '{print $1}' $i`
echo $i;
# echo $filename;
# if [ ]
done
./findMax.sh /home | awk '{print $2}'
统计报表:合计每人1月工资,0:manager,1:worker
Tom 0 2012-12-11 car 3000
John 1 2013-01-13 bike 1000
vivi 1 2013-01-18 car 2800
Tom 0 2013-01-20 car 2500
John 1 2013-01-28 bike 3500
awk '{split($3,date,"-");if(date[2]=="01"){name[$1]+=$5;if($2=="0"){role[$1]="M"}else{role[$1]="W"}}} END{for(i in name){print i "\t" name[i]"\t" role[i]}}' awk.txt
shell
shell bash 解释器,启动器 解释器: 用户交互输入 文本文件输入 脚本本质:
#! /bin/bash
#! /usr/bin/python
读取方式: 当前shell:source/. 新建子shell:/bin/bash file / ./file.sh 《chmod +x file.sh》 函数 命令概念总结
脚本是一个文本文件!
#!/bin/bash
./testFile
#! /bin/bash (/usr/bin/python)
先启动/bin/bash -f testFile
~~ 新开启一个shell :然后执行source testFile
- 文本流&重定向
- 变量
- 引用&命令替换
- 退出状态&逻辑判断
- 表达式
- 流程控制
文本流&重定向
重定向:不是命令 程序自身都有I/O 0:标准输入 1:标准输出 2:错误输出 控制程序I/O位置 一切皆文件 /proc/$$/fd 程序是否处理I/O? 绑定顺序:从左到右
输出重定向: 修改程序的1或2
> 覆盖源
>> 追加
&> , >&
输入重定向:
< 一个脚本 .sh .py
<< 后缀匹配结束
read bb 0<<ooxx
adfjadlfj
asdjf;lasjdf
asdfjdlasfkj
jdsf;
ooxx
<<<
read aa 0<<<"public void"
- exec
- 替换当前shell
变量
变量
- 本地 本地: 当前shell拥有 生命周期随shell name=god 局部: 只能local用于函数 val=100
- 位置:
${}
$1,$2
,${11}
环境变量导出
环境变量:env,printenv,export export定义变量 导出到子shell
fork() Copy On Write O(1)
parent 3g ==> child 3g 环境变量
- 进程 子进程 引用传递 环境变量
- 指针地址的引用
- Copy On Write 写时复制
- 物理计算机= 内存条 = 线性地址空间
- 物理地址 虚拟地址 映射关系
- CPU MMU 内存管理单元
- 写时复制,并无复制那么高的成本,是更改的指针引用
- 父进程启动,增加变量a = 2 ,在内存中开辟一个空间
2
,父进程指针指向此地址的, - 在使用
/bin/bash
开辟子进程后,子进程的a 同样指向内存中地址,当子进程中修改a的值后,在内存中,开辟一个新值的空间,将子进程指针指向此地址
- 父进程启动,增加变量a = 2 ,在内存中开辟一个空间
- 父进程,子进程。。 均为系统进程 维护虚拟地址
- java
适用于函数 unset:取消变量 set:查看shell的变量
命令替换:
- 接收变量等
- 反引号:
ls -l /
" lineq=
ls -l|wc -l"
$(ls -l /)
- 可以嵌套
- 反引号:
算术表达式
let 算术运算表达式
let C=$A+$B
$[算术表达式]
C =$[$A+$B]
$((算术表达式))
C=$(($A+$B))
expr 算术表达式
注意:表达式中各操作数及运算符之间要有空格。而且要使用命令引用
C=`expr $A + $B`
help let
条件表达式
help test
test 15 -gt 8 && echo 'is true'
[test 15 -gt 8] && echo 'is true'
[ expression ]
test expression
[[ expression ]]
help test
脚本 函数
特殊:
位置shell
$#
:位置参数个数$*
:参数列表,双引号引用为一个字符串$@
:参数列表,双引号引用为单独的字符串$$
:当前shell的PID:接收者 $BASHPID:真实 管道echo $?:
上一个命令退出状态 0:成功 other:失败
[root@dock01 app]# cat param.sh
#!/bin/bash
echo $$
echo $#
echo $*
echo $@
echo $1
echo 'end'
[root@dock01 app]# ./param.sh 1 2 3 4 5 6 7 8 9
9307
9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1
end
[root@dock01 app]#
- add User Shell
#!/bin/bash
userName=$1
echo 'add $userName'
# 添加用户
# useradd
# 用户密码同用户名
# 静默运行脚本
# 避免捕获用户接口
# 程序自定义输出
#!/bin/bash
[ ! $# -eq 1 ] && echo "args error" && exit 2
id $1 >& /dev/null && echo "user:$1 exist~!" && exit 3
! useradd $1 >& /dev/null && echo "add user error!" && exit 7
echo $1 | passwd --stdin $1 >& /dev/null
echo "user:$1 add ok ~!"
流程控制
shell if
if [ express ] ; then xxx ; else xxx ; fi
[root@dock01 app]# if [ 3 -eq 6] ; then echo okk; else echo no ok; fi
bash: [: missing `]'
no ok
[root@dock01 app]# if [ 3 -eq 6 ] ; then echo okk; else echo no ok; fi
while for
for (( exp1; exp2; exp3 )); do COMMANDS; done
[root@dock01 app]# for ((i=1;i <11 ; i++ )) ; do echo ${i} ; done
for NAME [in WORDS ... ] ; do COMMANDS; done
case
循环遍历文件每一行:流程控制语句 定义一个计数器num 打印num正好是文件行数
管道 重定向 命令替换
#!/bin/bash
num=0
oldIFS=$IFS
IFS=$'\n'
for i in `cat file.txt`;do
echo $i
((num++))
done
echo "num:$num"
IFS=$oldIFS
echo "--------------"
num=0
lines=`cat file.txt | wc -l `
for ((i=1;i<=lines;i++));do
line=`head -$i file.txt | tail -1`
echo $line
((num++))
done
echo "num:$num"
echo "--------------"
num=0
while read line ;do
echo $line
((num++))
done < file.txt
echo "num:$num"
echo "--------------"
export num=0
cat file.txt | while read line ;do
echo $line
((num++))
done
echo "num:$num"
#!/bin/bash
oldIFS=$IFS
IFS=$'\n'
flg=0
for i in ` du -a $1 | sort -nr`;do
fileName=`echo $i | awk '{print $2}'`
if [ -f $fileName ];then
echo $fileName
flg=1
break
fi
done
IFS=$oldIFS
if [ $flg -eq 0 ];then
echo "not find" && exit 2
else
exit 0
fi
1,花括号 mkdir -p sdfsdf/{a,b,c}sdfsdf 2,波浪线 cd ~god 3,变量&参数 $ $$ ${}(.....) 4,命令替换 ls -l echo $path
5,算术扩展 num=((3+4)) 6,word拆分,IFS 7,路径 *(零到多个任意字符)? 8,引用删除 echo "hello" *,重定向 >