北京线下第三期_Bash 基础与应用_20180624

课堂笔记

变量

# 如果变量不存在也可以直接使用
echo $x

a=1
echo $a
b=seveniruby
echo $b
c=hello from testerhome
echo $c
c="hello from testerhome"
echo $c
c='hello from testerhome'
echo $c
单双引号的区别
c='hello $a from testerhome'
echo $c
c="hello $a from testerhome"
echo $c

变量使用 花括号的使用

echo ${a}
echo $a_1
echo ${a}_1
echo $a _1  #如果没歧义,可以简化写法
echo $ddd  #变量未定义,仍然可以使用

预定义变量

pwd 是一个命令 表示当前的目录
$PWD 是一个预定义的变量,PWD=pwd echo $PWD
$USER 当前用户名
$HOME 当前用户的家目录
$PATH 指的是环境变量

反引号

echo `ls`
e=`ls`
echo $e
pwd
e=`pwd`
echo $e
echo $USER 
echo $HOME    #等同于 echo ~

which命令

用于查找并显示给定命令的绝对路径
例子:
which python

vim 1.sh //可以用touch代替
chmod +x 1.sh
which 1.sh  #没有在环境变量里
export PATH=$PATH:$PWD
which 1.sh

根目录 执行1.sh 可以tab补全

数组变量

array=(1 2 3 4 5)
echo $array
echo ${array[@]}
echo ${array[2]}
echo ${#array[@]}
echo ${array[*]}
echo ${#array[*]}

array=(`ls`)  ls命令返回赋给一个数组,所以用()
array=`ls`     ls命令的返回付给了一个字符串

@与*的区别:
\反斜杠,一般情况下将特殊字符变成一般字符,转义符
例子:
echo -e “a\nbb”
-e 是开启转义模式
如果没有 -e
echo “a\nbb”
想要打印一个 a"bb
echo -e "a\“bb”
echo “a\\b”

** $(ls) 与 ls **
这两个都是用作命令替换的,换言之就是重组命令行的
执行顺序是先执行反引号里的命令,然后将其结果替换出来,再重组成新的命令行
举例:

echo my dir is `ls`
echo my dir is  $(ls)

在操作上,这两个东西都能达到相应的效果
对比:

  1. ``比较容易和双引号搞混
  2. 在多层次的复合替换中,``必须要额外的转义,而$()不需要
  3. $()的弊端是,不是所有的类unix系统都支持,但是``都支持
    反引号很重要,可以引用很多命令

$(())是对变量进行操作
例子:

a=2;b=3
echo $((a+b))

echo $((2+3))

a=5;b=7;c=2
echo $((a+b*c))
echo $(($a+$b*$c))
#这两个是等价的

(())重新定义变量的值,算术运算,还可以用于算数比较

({1…10})
等价于seq 1 10
seq命令用于产生从某个数到另外一个数之间的所有整数

变量类型

a=1
echo $a
echo "$a"
b=true
f=false
echo $b
echo $f

数字型变量操作

a=1
echo $((a+1))
((a=a+1))
echo $a
((a=a+2))
echo $a
((a=a*3))
echo $a

a=5;b=7
((a++));echo $a
((a--));echo $a
((a<b));echo $? 0  
shell下的浮点数不支持
echo $((2/3))

awk 'BEGIN{print 2/3}'

字符串操作

s="hello from testerhome"
echo $s
echo ${s:6}
echo ${s:6:3}
echo ${#s}

掐头去尾
${}用于变量替换

echo ${s#hello}
echo "${s#hello}"
echo "${s#*o}"
echo "${s#*m}"
echo "${s##*m}"  贪婪匹配
echo "${s%home}"
echo "${s%h*}"
echo "${s%%o*}"

内容替换

echo $s
echo ${s/testerhome/seveniruby}
echo ${s/from/to}
echo ${s/h/xxx}
echo ${s//h/xxx} 贪婪匹配

布尔变量

a=true
a=false
echo $?
ls
echo $?
ls ffffff
echo $?
true
echo $?
false
echo $?
[ 3 -eq 2 ]
echo $?
echo $? 
((3>2));echo $?
((3>20));echo $?

字符串比较

a=testerhome
b="hello from testerhome"
echo $a
echo $b
[ "$a" = "$b" ]
echo $?
[ "$a" != "$b" ]
echo $?
[ -n "$b" ]
echo $?
[ -z "$b" ]
echo $?

[[ "$b" == h* ]]
echo $?
[[ "$b" == m* ]]
echo $?

逻辑判断

ge 大于等于
eq 等于
ne 不等于
gt 大于
lt 小于
le 小于等于

-a 逻辑与 等价于 &&

[ 2 -ge 1 ];echo $?
[ 3 -ge 4 ];echo $?
[ 2 -ge 1 -a 3 -ge 4 ]

-o 逻辑或 等价于 ||

[ 2 -ge 1 ];echo $?
[ 3 -ge 4 ];echo $?
[ 2 -ge 1 -o 3 -ge -4];echo $?

[[ 2 -ge 1 && 3 -ge 4 ]];echo $?
[[ 2 -ge 1 || 3 -ge -4] ];echo $?

!逻辑非

[ ! 2 -ge 1 ];echo $?

内置判断

ls
[ -e test ]
echo $?
[ -e test2 ]
echo $?
[ -d test ];echo $?
[ -f test ];echo $?

-普通文件
d目录文件
b块设备文件,硬件设备之类的文件
l链接link设备
p命名管道文件
s套接字文件,比如socket

逻辑控制

if结构

if [ -e test ];then echo exist;else echo not exist;fi
if [ -e test ]
then
echo exist
else
echo not exist
fi

分号,按像上箭头,shell把上面的命令变成了一行

if ls test;then echo exist;else echo not exist;fi
简单逻辑可以用&& || 代替

ls test && echo exist || echo not exist

[ -e test ] && echo exist || echo not exist
[ -e test ] || echo exist && echo not exist

&&前面的命令执行成功 为真 才会执行&&后面的命令
|| 前面的命令执行失败,为假,才会执行||后面的命令
[ -e test ] 执行成功,所以|| echo not exist 就不执行了
|| echo not exist没执行,等于不存在
[ -e test ] 因为执行成功了所以执行了 && echo not exist
不等价于if else

if [ ! -e test];then echo not exist;else echo exist;fi
echo "1" &&  echo "2" ||  echo "3" && echo "4" || echo "5" || echo "6" && echo "7" && echo "8" || echo "9" 

输入 history 查看之前输入过的所有指令
有一条指令,ctrl+e跳到指令末尾,ctrl+a跳到指令开头

ls /home/natuo/.bash_histroy
less ~/.bash_history
tail ~/.bash_history

less命令 查看文件命令,文件分页浏览,可以使用pageup和pagedown翻页,按上下键翻行,按q退出
tail 命令 用于查看文件的末尾几行 tail -n 5 ~/.bash_history 查看文件末尾5行

ctrl+c 中断程序

for 循环

for ((i=0;i<10;i++));do echo $i;done
for (i=0;i<10;i++);do echo $i;done   //注意是2个括号,1个括号语法报错
array=(1 2  3 4 5)
for((i=0;i<${array[@]};i++));do echo $i;done  //这个会报错,思考下为什么报错
for((i=0;i<${#array[@]};i++));do echo ${array[i]};done
array=(a b c d e)
for((i=0;i<${#array[@]};i++));do echo ${array[i]};done

for 遍历

for x in ${array[@]};do echo $x;done  
for x in `ls`;do echo $x;done

touch 1
#touch 创建文件
ls
touch 2 3
for x in `ls`;do echo $x;done
for x in *;do echo $x;done
  • 通配符 表示任意数量的任意字符
for x in "`ls`";do echo $x;done
ss=(aa bb cc "sss dd");for x in ${ss[@]};do echo $x;done
ss=(aa bb cc "sss dd");for x in "${ss[@]}";do echo $x;done

while循环

i=0
while  [ $i -lt 3 ];do echo $$i;((i=i+1));done

#vim 1里面写a b c d e
while read line;do echo $line;done < 1
while read line;do echo $line;done  //等待输入

read read命令接收标准输入(键盘)的输入 ,一次只读一行
read x
输入一个东西
echo $x
read line
输入一个东西
echo $line

read -p 后面可以加个字符串

ead -p "hahaha:" x;echo 我刚刚输入了:$x

read x < 1
echo $x

退出控制

for f in *;do echo $f;done
for f in *;do echo $f;[ -d $f ] && break;done      //不用这个例子
for f in *;do echo $f;[ -d "$f" ] && continue;echo $f is file;done   //不用这个例子
for f in *;do echo $f;if [ -d $f ];then break;fi;done    //用这个 -d表示文件是不是一个目录
for f in *;do echo $f;if [ -f $f ];then echo $f is file;else continue;fi;done

shell运行环境概念

ls
echo $$ 查看当前shell的进程号  
bash
echo $$
exit
echo $$

()是在子shell中运行的,()中的内容执行完毕后,子shell消亡
(a=1)
echo $a 不是1

(a=1;echo $a);echo $a

{}是在当前shell中执行的
{ a=1;echo $a; };echo $a 语句块

&后台执行

for ((i=0;i<10;i++));do echo $i;sleep 2;done
for ((i=0;i<10;i++));do echo $i;sleep 2;done &
echo 随便打点什么
echo 随便打点什么

$! 运行在后台的最后一个作业的pid

echo $!
sleep 10
echo $!
sleep 10 &
echo $!

ps 命令
用于报告当前系统的进程状态
-e 选项 显示所有进程
-f 选项 全格式

sleep 50 &
echo $!
ps -ef | grep 上面的pid    //选讲

sleep 10 &
jobs
jobs 命令 用于查看任务状态
sleep 50 &
jobs

ctrl+z 前台执行的程序 放到后台,使用后,改程序暂停执行
bg 1 让一个后台暂停的程序 在后台继续执行

fg 1 将后台命令调至前台执行
vim 1编辑中,临时要做其他事,用ctrl+z存放到后台
fg 1

echo $$
ps -ef |grep xxx pid自己查

echo $PWD
echo $USER
echo $HOME

echo $+tab+tab

shell 环境变量

set 命令作用主要是显示系统中已经存在的shell变量
env 显示(设置)用户变量变量
env | grep -i path
可以看到环境变量

环境变量设置

一般用于简化操作,不需要到指定的目录下去寻找需要运行的程序
有4种方法:

1.修改profile文件
#profile文件在 /etc/目录下
修改profile文件可能需要修改属组的权限
sudo chmod 777 profile
文件中添加 export PATH=$PATH:/home/natuo/exp/
#保存退出
echo $PATH 查看环境变量
#生效方法
source /etc/profile
#展示生效后的 echo $PATH
关闭当前窗口后,重新打开该窗口,echo $PATH 里不会有新添加的path,重启后生效
#展示根目录运行脚本
#生效期限: 永久有效
#对所有用户有效

2.修改environment文件
sudo chmod 777 environment
vim /etc/environment
在path路径中添加:/home/natuo/exp
保存退出
#生效方法:系统重启
#有效期限:永久有效
#对所有用户有效
展示根目录运行脚本

3. 修改.bashrc文件
#.bashrc文件在当前用户根目录
ls -al查看
vim .bashrc
最后一行添加 export PATH=$PATH:/home/natuo/exp/
#保存后退出
echo $PATH 展示当前环境变量 # 未生效
#生效方法
关闭当前窗口,重新打开生效
输入source ~/.bashrc生效
#echo $PATH 展示当前环境变量 #已生效
#有效期限 永久有效
#只对当前用户有效
根目录执行脚本 展示生效脚本

4. export命令
语法:export [-f -n -p] [变量名称]=[变量设置值]
例子:
mkdir exp
chmod [参数] + filename
vim a.sh
里面写一些内容 #!/bin/bash echo testerhome
bash a.sh 执行一下脚本
export PATH=$PATH:/home/natuo/exp/
export #查看
#根目录执行该脚本
#立即生效
#有效期限为临时改变,只能在当前终端窗口中有效,当前窗口关闭后,恢复原有path的配置
#只对当前用户生效

echo $PATH # 关闭窗口
echo $PATH

vim常规操作
wq 保存退出
q 不保存退出
q! 强制退出
wq! 强制保存退出
setnu 显���行号
set nonu 不显示行号
gg 调到文件头
G 调到文件尾
v 进入剪切复制模式
v+j/k/h/l 进行选中或者键盘上的上下左右
d 剪切
y 复制
p 黏贴
^选中当前行,光标跳到行首 等同于键盘上的HOME
$ 选中当前行,光标跳到行尾 等同于键盘上的END

shell 输入输出

vim 1
里面写 hello from testerhome 保存退出

echo "seveniruby" > 1
cat 1
echo "testerhome" > 1
cat 1
会覆盖
echo "testerhome" >> 1
echo "testerhome" > 1

read x < 1
echo $x

管道

grep t 1(这个1是文件名)
grep home 1

grep home  #按回车,后面等待输入,如果输入的东西能匹配到,会显示出来
sss
fff
home
testerhome
homeland

echo testerhome
echo testerhome | grep home

解释一下管道命令的执行顺序

文件描述符

0 标准输入 文件描述符0理解为我和计算机交互时的输入,而这个输入默认是指向键盘的;
1 标准输出 文件描述符1理解为我和计算机交互时的输出,而这个输出默认是指向显示器的;
2 错误输出 文件描述符2理解为我和计算机交互时,计算机出现错误时的输出,而这个输出默认是和文件描述符1指向一个位置;

ls
ls  > 1
ls ddd > 1
cat 1
ls ddd > 1 2>&1
ls ddd > /temp/x 2>&1

command 1>a 2>&1可以理解为执行command产生的标准输入重定向到文件a中,标准错误也重定向到文件a中
那么是否可以理解为 command 1>a 2>a呢,其实不是,他们是有区别的,区别就在于 2>&1这种方式只打开一次a,而第二种方式会打开2次a
并且我们知道,>重定向后,之前的内容会被覆盖,&1的含义就可以理解为标准输出的引用,引用的内容就是重定向标准输出打开的a,那么从文件
读写的效率来说,2>&1这种方式会比 command 1>a 2>a效率更高

通配符
通配符是一种特殊语句,主要用于字符串的匹配,一般用于文件名
最常用的通配符 * ?

  • 代表0个或任意个任意字符
    ? 代表任意一个字符
    [] 代表中括号中的任意一个字符
    [^] 取反

先创建几个空文件

touch 1 2 2333 aa 22222 a aaaaaa

echo *              表示当前目录下的所有文件
echo ?              表示当前目录下文件名为1个字符的文件
echo ??             表示当前目录下文件名为2个字符的文件
echo te*           user开头的所有文件,讲的时候可以用t开头的代替,因为我目录下有很多t开头的文件
echo a?*           因为*可以代表0个,字符,所以 echo a* 会匹配出 文件名为a的文件,echo a?* 只能匹配出 超过一个a长度的文件
ehco 2??            当前目录下开头为2,文件名长度为3个字符的文件
echo 2*             当前目录下开头为2,长度任意的文件打印出来
for i in te*;do echo $i;done

用ls 是一样的

三剑客

grep是一种强大文本搜索工具,支持正则表达式
awk主要用于数据切片
sed 主要是用于数据修改

grep

grep是一种强大文本搜索工具,支持正则表达式

grep家族里有grep egrep fgrep
grep 标准grep内容 等价于 grep -e
egrep 扩展grep命令,支持基本及扩展的正则表达式 等价于 grep -E 推荐使用这种方式
fgrep 快速grep命令,允许查找字符串而不是一个模式,其实速度和grep差不多

命令格式
grep [options] pattern file
options 表示选项,具体看下面的内容
pattern 表示要匹配的模式(包括目标字符串,变量或正则表达式)
file 表示要查询的文件名,可以是一个或多个,pattern后面的所有字符串参数都会被理解为文件名

// -i -o -n

# -h 当搜多多个文件时,不显示匹配文件名前缀
# -l  只列出含有匹配的文本行的文件的文件名,而不显示具体的匹配内容
# -s 不显示关于不存在或者无法读取文件的错误信息
# -x 匹配整个文本行
# -r 递归搜索,搜索当前的目录和子目录
# -q 禁止输出任何匹配结果,而是以退出码的形式表示搜索是否成功,其中0表示找到了匹配的文本
# -b 打印匹配的文本行到文件头的偏移量,以字节为单位
# -E 开启扩展正则表达式
# -i  忽略大小写
# -v 只打印没有匹配的,匹配的反而不打印
# -n 显示行号
# -w 完全匹配 被匹配的文本只能是单词,而不能是单词中的一部分,如文本中有liker,而只搜寻like,就可以使用-w来避免匹配liker   
# -c 显示总共有多少行被匹配到了,而不是显示被匹配的内容,如果使用-cv选项则是显示有多少行没有被匹配到
# -o 精准匹配 只显示被模式匹配到的字符串
# --color 将匹配到的内容以颜色高亮显示
# -A n  显示匹配到的字符串所在行及其后n行
# -B n  显示匹配到的字符串所在的行及其前n行
# -C n  显示匹配到的字符串所在的行及其前后各n行
# -F 不支持正则表达式,将模式按照字面意思匹配
# -P 支持Perl正则表达式

例子

vim text1.txt
hello from testerhome
email
wulala
little

vim text2.txt
hello from testerhome,this is for grep test

vim text3.txt
hello from testerhome
tyrone

chmod 775 text1.txt text2.txt text3.txt

grep -i "hello from testerhome" text1.txt                                 # 忽略大小写
grep -i "HELLO FROM TESTERHOME" text1.txt
grep -i "hello from testerhome" text1.txt text2.txt text3.txt

grep -o "hello from testerhome" text1.txt                                # 精准模式 只显示匹配到的字符串
grep -o "hello from testerhome" text1.txt text2.txt text3.txt 

grep -io "hello from testerhome" text1.txt                                # 精准匹配并且忽略大小写
grep -io "HELLO FROM TESTERHOME" text1.txt

grep -i 'hel' text1.txt
grep -o "hel" text1.txt
grep -io "hel" text1.txt

echo abcd | grep -o c  
echo abcdefc | grep -o "c."  

正则表达式

符号"."
匹配任意一个字符,除了换行符,但是需要注意的是,在sed中不能匹配换行符,但是在awk中可以匹配换行符,

符号""
表示前边字符有0个或多个。".
“表示任意一个字符有0个或多个,也就是能匹配任意的字符,类似shell通配符中的”*",可以匹配任意字符
类似shell通配符中的"?",匹配任意一个字符。

echo abcdefc | grep -o “c.*”

扩展正则
符号"?"
表示前面字符有0个或者1个

符号"+"
表示前面字符有1个或多个

echo abcdefc | grep -oE "c.*?"  
echo abcdefcxx | grep -oE "c.*?" 

curl  发送http请求的工具

curl http://www.baidu.com  默认get请求
curl http://www.baidu.com | less
curl --help
curl --help | less
curl http://www.baidu.com | less   
curl  -X POST http://www.baidu.com | less        
curl  -X POST http://www.baidu.com > /tmp/1   

curl http://www.baidu.com/s?wd=mp3

测试百度 mp3这个单词的索引量

新建文件

vim /tmp/baidu.keyword
mp3
mp4
rest-assured
android
ios

保存退出

while read k;do echo $k;done < baidu.keyword
curl http://www.baidu.com/s?wd=android
while read k;do echo $k;curl http://www.baidu.com/s?wd=$k;done < baidu.keyword

curl http://www.baidu.com/s?wd=mp3 | grep "结果约"
curl http://www.baidu.com/s?wd=mp3 | grep -o "结果约"  精准匹配

culr 会有一些统计信息,我们把我们需要的标准输出 重定向一下
curl http://www.baidu.com/s?wd=mp3 2>&1| grep -o "结果约"

或者 使用 curl -s 选项也可以

curl http://www.baidu.com/s?wd=mp3 2>&1| grep "结果约"

正则表达式
符号"[]"
"[]"中括号中可以包含表示字符集的表达式,使用方法大概有以下几种:
[a-z]: 表示a-z字符中的一个,也就是小写字母
[0-9]: 表示0-9字符中的一个,也就是表示数字
[A-Z]: 表示大写字母
[a-zA-Z]: 表示普通字符,包括大小写字母和数字
[abc]: 表示字符a或字符b或字符c
[^0-9]: 表示非数字类型的字符,^表示取反的意思,只能放在中括号的开始的地方才有意义
[-cz]: 表示字符-或字符c或字符z,这和[c-z]是有区别的

curl http://www.baidu.com/s?wd=mp3 2>&1| grep -o "结果约[0-9]*"

但是因为 我们需要的结果中间有,号

curl http://www.baidu.com/s?wd=mp3 2>&1| grep -o "结果约[0-9,]*"
curl http://www.baidu.com/s?wd=mp3 2>&1| grep -oE "结果约[0-9,]+" 
curl http://www.baidu.com/s?wd=mp3 2>&1| grep -oE "结果约[0-9,].*?"   // 实际演示版本可能需要这种匹配方式

curl http://www.baidu.com/s?wd=mp3 2>&1| grep -o "结果约[0-9,]*"|grep -o "[0-9]*" | while read x; do printf $x; done;

printf 与 echo
echo 自带一个换行符
printf 需要显示指定一个换行符\n

while read k;do echo $k;curl=http://www.baidu.com/s?wd=$k 2>&1;done < baidu.keyword | grep -o "结果约[0-9,]*" | grep -o "[0-9]*" | while read x;do printf $x;done
while read k;do echo $k;curl=http://www.baidu.com/s?wd=$k 2>&1 | grep -o "结果约[0-9,]*" | grep -o "[0-9]*" | while read x;do printf $x;done;done < baidu.keyword

题目1:打印出来没有换行符,很难看对不对,大家思考一下,怎么让他打印出来变得好看一点

while read k;do echo -e "\\n$k";curl=http://www.baidu.com/s?wd=$k 2>&1 | grep -o "结果约[0-9,]*" | grep -o "[0-9]*" | while read x;do printf $x;done;done < baidu.keyword
while read k;do echo -e "\\n$k";curl=http://www.baidu.com/s?wd=$k 2>&1 | grep -o "结果约[0-9,]*" | grep -o "[0-9]*" | while read x;do printf $x;done;printf  "\\n";done < baidu.keyword

awk

awk把文件逐行读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理

调用awk的几种方式
awk ‘{pattern + action}’ (filename)
#pattern表示在数据中查找的内容
#action 表示在找到匹配内容时所执行的一系列命令

#命令行方式
awk [-F field-separator] ‘commands’ input-file(s)
#commands: 是真正的awk命令
#[-F域分隔符]是可选的 在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域,通常在不指明-F域分隔符的情况下,默认的域分隔符是空格
#input-files(s)是待处理的文件

echo '123|456|789' | awk '{print $1}'                       //默认分隔符为空格
echo '123 |456|789' | awk '{print $1}'                      //默认分隔符为空格
echo '123|456|789' | awk -F '|' '{print $1}'
echo '123|456|789' | awk -F '|' '{print $2}'
echo '123+456_789m4444' | awk -F '+|_' '{print $2}'                  // 这里的|意思是或的意思
echo '123+456_789m4444' | awk -F '+|_|m' '{print $3}'
echo '123+456_789m4444' | awk -F '+|_|m' '{print $4}'

 curl http://www.baidu.com/s?wd=mp3 2>&1 | grep "结果约" | awk '{print $1}'   //执行结果是 <div
 curl http://www.baidu.com/s?wd=mp3 2>&1 | grep "结果约" | awk '{print $1}'   //执行结果是 class xxxxxxxxx
 curl http://www.baidu.com/s?wd=mp3 2>&1 | grep "结果约" | awk '{print $1}'   //执行结果是 OP_LOG

默认的把空格 当成分隔符

// 请大家练习一下
例子:

last -n 5  # 显示登陆的用户信息
last -n 5 | awk '{print $1}'

#awk工作流程就是 读入带有"\n"换行符分割的一条记录,然后将记录按照指定的域分隔符进行分割,$0表示所有的域,$1表示第一个域,$2表示第二个域,$n表示第n个域 \
默认的域分隔符是空格"空白键或者tab制表符键"

etc/passwd 存储的是操作系统的用户信息

cat /etc/passwd | awk -F ':' '{print $1}'

#-F 指定域分隔符为":"

cat /etc/passwd | awk -F ':' '{print $1" "$7}'

#需要切片第一列与最后一列,中间以空格隔开,""内可以填入任何字符

cat /etc/passwd | awk -F ':' '{print $1"\\t"$7}'  以制表符隔开  

curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约
curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $1}'    //没有 别切割掉了
curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $2}'     //这是我们想要的
curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $3}'     //切割的剩余部分

curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $2}' | awk -F ','  '{print $0}'
curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $2}' | awk -F ','  '{print $1,$2,$3}'
curl http://www.baidu.com/s?wd=mp3 2>&1 | grep 结果约 | awk -F '个|约' '{print $2}' | awk -F ','   '{print $1$2$3}'

//练习
把当前页面所有的评价条数打印出来

curl http://www.baidu.com/s?wd=mp3 2>&1 | grep "条评价" | awk -F 'data-from="ps_pc4">' '{print $2}' | awk -F '条' '{print $1}'

//只讲这些

# awk内置变量
# FS                     设置输入域分隔符,等价于命令行 -F选项  
# NF                     浏览记录的域的个数
# NR                     已读的记录数
# RS                     控制记录分隔符   行记录分隔符
# NR                     已读的记录数
# NF                     浏览记录的域的个数
------------------------------------------------------------------------------------
# ARGC                命令行参数个数
# ARGV                命令行参数排列
# ENVIRON           支持队列中系统环境变量的使用
# FILENAME          awk浏览的文件名
# FNR                   浏览文件的记录数
# FS                     设置输入域分隔符,等价于命令行 -F选项  
# NF                     浏览记录的域的个数
# NR                     已读的记录数
# OFS                   输出域分隔符
# ORS                   输出记录分隔符
# RS                     控制记录分隔符   行记录分隔符
# $0表示整条记录,$1表示第一个域,$2表示第二个域,$n表示第n个域
--------------------------------------------------------------------------------------
echo '123|456|789' | awk 'BEGIN{FS="|"}{print $2}'
echo '123|456|789' | awk 'BEGIN{RS="|"}{print $1}'

RS 控制记录分隔符 行记录分隔符
找到某某标志,让每个某某后的内容重新变成一行
例子
1.txt
echo “a|b|c” | awk ‘BEGIN{RS="|";}{print $0}’
找到|标识,让|后面的内容重新变成一行
ORS 输出记录分隔符,或者叫输出字段分隔符
可以把他理解为RS的逆向
1.txt

echo "a|b|c" | awk 'BEGIN{RS="|";ORS="_"}{print $0}'
echo -e "a\\nb\\nc" | awk 'BEGIN{ORS="_"}{print $0}'

echo $PATH
echo $PATH | awk 'BEGIN{RS="="}{print $0}'
echo $PATH | awk 'BEGIN{RS="=";ORS="_"}{print $0}'
echo $PATH | awk 'BEGIN{RS=":"}{print $0,NR,NF}'
echo $PATH | awk 'BEGIN{RS=":";FS="/"}{print $0,NR,NF}'
awk 'BEGIN{print 1000/256}'
awk 'BEGIN{print 1000/256}{print $0}' 是执行不了的

//练习 把中间的数字加起来

echo -e "1|2|3\\n4|5|6\\n7|8|9" | awk -F '|' 'BEGIN{total=0}{total=total+$2}END{print total}'
echo -e "1|2|3\\n4|5|6\\n7|8|9" | awk -F '|' 'BEGIN{total=0}{total=total+$2;print $2}END{print total}'

curl http://www.baidu.com/s?wd=mp3 | grep 条评价 | wc -l
curl http://www.baidu.com/s?wd=mp3 | grep 条评价 | awk -F '条评价' '{print $1}'

NF 浏览记录的域的个数
$NF 表示的最后一个域(列),即输出最后一个字段的内容

curl http://www.baidu.com/s?wd=mp3 | grep 条评价 | awk -F '条评价' '{print $1}' | awk -F '>' '{print $NF}'

// 把记录数加起来

curl http://www.baidu.com/s?wd=mp3 | grep 条评价 | awk -F '条评价' '{print $1}' | awk -F '>' 'BEGIN{t=0}{t=t+$NF;print $NF}'END'{print t}'

sed

sed 按照指令,来处理、编辑文本文件
sed [选项] ‘command’ 文件名称

sed会一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区,称为"模式空间",接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容 \
送往屏幕,接着处理下面一行,这样不断重复,直到文件末尾,文件内容并未改变,除非使用重定向存储输出

s命令 也是最最常用的命令
用法:斜线/隔出两个字符串,用第二个替换第一个(每行默认只替换第一处)

echo "cat dog fish cat"
echo "cat dog fish cat" | sed 's/cat/wulala/'
echo "cat dog fish cat" | sed 's/cat/wulala/g'

//练习

echo "123|456|789" | sed 's/|/+/'
echo "123|456|789" | sed 's/|/+/g'
echo "123|456|789" | sed 's/[48]/x/g'

curl http://www.baidu.com/s?wd=mp3 | grep 结果约.*个
curl http://www.baidu.com/s?wd=mp3 | grep 结果约.*个 | awk -F '个|约' '{print $2}' 
curl http://www.baidu.com/s?wd=mp3 | grep 结果约.*个 | awk -F '个|约' '{print $2}'  | sed 's#,##g'
curl http://www.baidu.com/s?wd=mp3 | grep 结果约.*个 | awk -F '个|约' '{print $2}'  | sed 's/,//g'

#或者/意思一样,随便用什么 常用/

//改文件

cat test.txt
sed 's/hello/A/' test.txt
cat test.txt

选项 -i
sed默认会把输入行读取到模式空间,简单理解就是一个内存缓冲区,sed子命令处理的内容是模式空间的内容,而不是直接处理文件内容。因此在sed修改模式空间内容之后,并不是直接写入修改输入文件,而是打印输出到标准输出。如果需要修改输入 \
文件,那么就可以指定-i选项

vim test.txt
hello from testerhome
hello hello from testerhome
wulala is a beautiful girl
today is sunday

保存退出

sed -i 's/hello/A/' test.txt
cat test.txt

sed -i.bak 's/hello/A/' test.txt

使用-i的时候,建议大家使用这个

更多工具

ps命令

sleep 100&
ps
ps -ef

pid ppid
sshd

ssh是一项服务

ps aux
显示其他用户启动的进程(a)
查看系统中属于自己的进程(x)
启动这个进程的用户和它启动的时间(u)

ps aux | less
ps aux | grep sleep
ps --help  
man ps  //帮助文档

ps aux命令显示的状态列中的Ss+,Rsl,R+,S<sl都是什么意思呢?(转)

D    不可中断     Uninterruptible sleep (usually IO)
R    正在运行,或在队列中的进程
S    处于休眠状态
T    停止或被追踪
Z    僵尸进程
W    进入内存交换(从内核2.6开始无效)
X    死掉的进程


<    高优先级
N    低优先级
L    有些页被锁进内存
s    包含子进程
+    位于后台的进程组;
l    多线程,克隆线程  multi-threaded (using CLONE_THREAD, like NPTL pthreads do)

R+ 正在运行的位于后台的进程组,或在队列中的进程
Ss 处于休眠状态且包含子进程
S< 处于休眠状态优先级比较高的进程

netstat命令
Linux netstat命令用于显示网络状态。

-t (tcp)仅显示tcp相关选项
l 仅列出有在 Listen (监听) 的服務状态
n 拒绝显示别名,能显示数字的全部转化成数字
p 显示建立相关链接的程序名

netstat -tlnp
ocal address      表示本地IP地址,IP地址前面为计算机名称,如例子中的Eagle。
foreign address  表示远程IP地址。

netstat -t
netstat -tnp

-c 每隔一个固定时间,执行该netstat命令。

netstat -c

netst -tn | grep ":22"
netst -tn | grep ":22" | wc -l

脚本编写

注释
注释 #
#之后的当前行代码不会被执行
多行注释可以使用 :<< 符号或字符
例子:

脚本里

:<< ads
echo 123
echo 456
echo 789
ads
echo 110

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 告诉系统说,就在当前目录找。

传入参数

$0 传递的是执行的文件名字;
$1 传递的第一个参数
$2 传递的第二个参数
$3 传递的第三个参数

$n 传递第n个参数
shell 默认传递9个参数

$* 表示所有的参数,不包含$0, 以一个单字符串显示所有向脚本传递的参数
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$# 传递到脚本的参数个数

$@与$*的区别
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。

vim test1.sh
echo "获取脚本执行的参数:$0";
echo "获取第一个参数:$1";
echo "获取第二个参数:$2";
echo "获取参数的个数:$#";
echo "获取到的参数(str):$*";
echo "获取到的参数(每一个参数都是一个str):$@";
echo "获取当前进程的ID号(PID):$$";

保存退出

作业

关闭