Linux
干货集散地

LINUX命令行与SHELL脚本编程大全.第三版.读书笔记.含源码

#du -h –max-depth=1 ./</pre>
#tail
#more
#head
#touch newfile
#cat
//查看文件file内容,找到分隔符: 以第三项倒叙排列
#sort -t ':' -k 2 -r file
#man df
#df –help
//查看当前文件夹下所有文件的总大小,并以可读的倒叙的形式排列
#du -sh * | sort -nr
#grep 'bluestep' file
//搜索包含bluestep的行,并显示行号
#grep -n 'bluestep' file
//搜索包含bluestep的总数
#grep -c 'bluestep' file
//搜索不包含bluestep的行
#grep -v 'bluestep' file
//搜索包含blue和head的行
#grep -e blue -e head 'bluestep' file
//搜索“os_login”在当前目录下所有文件,并显示行号
#grep -n -R "os_login" ./*
#grep -n -R "os_login" ./

#tar -cvf test.tar /dir1 /dir2
#tar -xvf test.tar /dir1 /dir2

//进程树
#ps –forest
//将进程列表置入后台
#(sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)&
#which ps
#type -a ps
#alias li='ls -li'
#$? 命令运行后的状态

//vim编辑器
?关键词
/关键词
:s/old/new/ vim编辑器会跳到old第一次出现的地方,并用new来替换。
:s/old/new/g:一行命令替换所有old。
:n,ms/old/new/g:替换行号n和m之间所有old。
:%s/old/new/g:替换整个文件中的所有old。
:%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。

//shfile内容如下

#!/bin/bash

var1=10.46
var2=43.67
var3=33.2
var4=71

var5=$(bc << EOF
scale = 4
a1 = ( $var1 * $var2)
b1 = $[$var1 * ($var2 – $var3)]
a1 + b1
EOF
)

echo The final answer for this mess is $var5

#chmod u+x shfile
./shfile

#rpm -qa > rpm.list
#sort < rpm.list
#rpm -qa | sort | more
#rpm -qa | sort > rpm.list
#expr 1 + 5

//重定向错误和数据,&包含STDOUT和STDERR
#ls -al test test2 test3 badtest 2> test6 1> test7
#ls -al test test2 test3 badtest &> test7

//第14章介绍了如何使用read命令读取用户在键盘上输入的数据。将STDIN重定向到文件后,
//当read命令试图从STDIN读入数据时,它会到文件去取数据,而不是键盘。
$ cat test12
#!/bin/bash
# redirecting file input

exec 0< testfile
count=1

while read line
do
   echo "Line #$count: $line"
   count=$[ $count + 1 ]
done
$ ./test12
Line #1: This is the first line.
Line #2: This is the second line.

//记录消息 -a追加
#who | tee -a testfile

//lsof会显示当前Linux系统上打开的每个文件的有关信息
#lsof -i :8080
//要想知道进程的当前PID,可以用特殊环境变量$$(shell会将它设为当前PID)。-a选项用来
//对其他两个选项的结果执行布尔AND运算,这会产生如下输出。
#/usr/sbin/lsof -a -p $$ -d 0,1,2

$cat test23
#!/bin/bash
# read file and create INSERT statements for MySQL

outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
   cat >> $outfile << EOF
   INSERT INTO members (lname,fname,address,city,state,zip) VALUES
('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
done < ${1}

当运行程序test23时,$1代表第一个命令行参数。它指明了待读取数据的文件。read语句
会使用IFS字符解析读入的文本,我们在这里将IFS指定为逗号。
脚本中另外两处重定向操作出现在同一条语句中:
cat >> $outfile << EOF
这条语句中包含一个输出追加重定向(双大于号)和一个输入追加重定向(双小于号) 。输
出重定向将cat命令的输出追加到由$outfile变量指定的文件中。 cat命令的输入不再取自标准
输入,而是被重定向到脚本中存储的数据。EOF符号标记了追加到文件中的数据的起止。
#./test23 members.csv

//信号相关
1 SIGHUP 挂起
2 SIGINT 中断
3 SIGQUIT 终止
9 SIGKILL 无条件终止
18 SIGTSTP 停止或暂停进程,但不终止进程
CTRL+C生成SIGINT信号,CTRL+Z生成SIGTSTP信号
kill -9 2343

//每次使用Ctrl+C组合键,脚本都会执行trap命令中指定的echo语句,而不是处理该信号并允许shell停止该脚本。
trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT

//要捕获shell脚本的退出,只要在trap命令后加上EXIT信号就行
trap "echo Goodbye…" EXIT

//在后台运行
#./test5.sh &

//查看哪些脚本正在后台运行
#ps

//即使终端退出也不停止进程
#nohup ./test1.sh &

#./test10.sh > test10.out &
#jobs -l

#./sh
CTRL+Z停止,显示作业id和状态,bg或fg后可加作业id后台或前台启动
#bg
#fg 2

//优先级
#nice -n -10 ./test4.sh > test4.out &
#ps -p 4993 -o pid,ppid,ni,cmd
#renice -n 10 -p 5055
#at -M -f test13b.sh now  //-M不显示输出信息
#atq //哪些作业正在等待
#atrm 18
#crontab -e
#crontab -l

可以用nohup命令阻止这种情况发生。该命令会拦截任何发给某个命令来停止其运行的信号
(比如当你退出终端会话时)。这样就可以让脚本继续在后台运行,即便是你已经退出了终端会话。
当你将进程置入后台时,仍然可以控制它的运行。 jobs命令可以查看该shell会话启动的进程。
只要知道后台进程的作业号,就可以用kill命令向该进程发送Linux信号,或者用fg命令将该进
程带回到该shell会话的前台。你可以用Ctrl+Z组合键挂起正在运行的前台进程,然后用bg命令将
其置入后台模式。


第三部分 Part 3
高级 shell 脚本编程

sed流编辑器(stream editor)
重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到
STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。

sed -e 's/brown/green/; s/dog/cat/' data1.txt
sed -f script1.sed data1.txt

//全局替换
sed 's/test/trial/g' data4.txt

//-n选项将禁止sed编辑器输出。但p替换标记会输出修改过的行。将二者配合使用的效果就是
//只输出被替换命令修改过的行。
sed -n 's/test/trial/p' data5.txt

//只有那些包含匹配模式的行才会保存在指定的输出文件中。
sed 's/test/trial/w test.txt' data5.txt


sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd
sed 's!/bin/bash!/bin/csh!' /etc/passwd

sed '2s/dog/cat/' data1.txt
sed '2,3s/dog/cat/' data1.txt
//如果想将命令作用到文本中从某行开始的所有行,可以用特殊地址——美元符
sed '2,$s/dog/cat/' data1.txt

grep Samantha /etc/passwd
Samantha:x:502:502::/home/Samantha:/bin/bash
//只有Samantha这行的bash被替换了
sed '/Samantha/s/bash/csh/' /etc/passwd

sed '2{s/fox/elephant/ s/dog/cat/}' data1.txt
sed '3,${
> s/brown/green/
> s/lazy/active/
> }' data1.txt

sed '3d' data6.txt
sed '2,3d' data6.txt
sed '3,$d' data6.txt
sed '/number 1/d' data6.txt
sed '/1/,/3/d' data6.txt

echo "Test Line 2" | sed 'a\Test Line 1'
echo "Test Line 2" | sed 'i\
> Test Line 1'

sed '$a\
> This is a new line of text.' data6.txt
sed '1i\
> This is one line of new text.\
> This is another line of new text.' data6.txt

sed '3c\
> This is a changed line of text.' data6.txt
sed '2,3c\
> This is a new line of text.' data6.txt

sed 'y/123/789/' data8.txt
echo "This 1 is a test of 1 try." | sed 'y/123/456/'

//打印命令最常见的用法是打印包含匹配文本模式的行
sed -n '/number 3/p' data6.txt
sed -n '2,3p' data6.txt

sed -n '/3/{
> p
> s/line/test/p
> }' data6.txt

//打印行号
sed '=' data1.txt

sed -n '/number 4/{
> =
> p
> }' data6.txt

//列出(list)命令(l)可以打印数据流中的文本和不可打印的ASCII字符
cat data9.txt
This    line    contains        tabs.
sed -n 'l' data9.txt
This\tline\tcontains\ttabs.$

sed '1,2w test.txt' data6.txt
sed -n '/Browncoat/w Browncoats.txt' data11.txt

//读取data12.txt所有文本到data6.txt匹配的行之后
sed '3r data12.txt' data6.txt
sed '/number 2/r data12.txt' data6.txt
sed '$r data12.txt' data6.txt

sed '/LIST/{
> r data11.txt
> d
> }' notice.std

gawk '{print $1}' data2.txt
gawk -F: '{print $1}' /etc/passwd

cat script2.gawk
{print $1 "'s home directory is " $6}
gawk -F: -f script2.gawk /etc/passwd

$ gawk 'BEGIN {print "The data3 File Contents:"}
> {print $0}
> END {print "End of File"}' data3.txt

cat script4.gawk
BEGIN {
print "The latest list of users and shells"
print " UserID \t Shell"
print "——– \t ——-"
FS=":"
}

{
print $1 "     \t "  $7
}

END {
print "This concludes the listing"
}

$ gawk -f script4.gawk /etc/passwd

正则表达式

//删除空白航行
sed '/^$/d' data5
//*表示出现0次或多次
echo "btt" | sed -n '/b[ae]*t/p'

gawk程序能够识别ERE模式,但sed编辑器不能

//*表示出现0次或1次,最多只能出现一次
echo "beet" | gawk '/be?t/{print $0}'

//可以出现1次或多次,但必须至少出现1次
echo "bet" | gawk '/be+t/{print $0}'

//e出现一次
echo "bt" | gawk –re-interval '/be{1}t/{print $0}'

//e最少出现一次,最多两次,如下两个都不打印
echo "beeet" | gawk –re-interval '/be{1,2}t/{print $0}'
echo "baeaet" | gawk –re-interval '/b[ae]{1,2}t/{print $0}'

//通道
echo "The dog is asleep" | gawk '/cat|dog/{print $0}'

//表达式分组
echo "Sat" | gawk '/Sat(urday)?/{print $0}'

//删除匹配行的下一行
sed '/header/{n ; d}' data1.txt
//N,将下一行和当前行放在模式空间,当成“一行”
sed 'N ; s/System.Administrator/Desktop User/' data3.txt

//匹配度两行都删除
sed 'N ; /System\nAdministrator/d' data4.txt
//只删除匹配的第一行
sed 'N ; /System\nAdministrator/D' data4.txt
//删除header匹配行前的空行匹配行
sed '/^$/{N ; /header/D}' data5.txt
//-n选项来阻止脚本输出,当多行匹配出现时,P命令只会打印模式空间中的第一行
sed -n 'N ; /System\nAdministrator/P' data3.txt

sed -n '/first/ {h ; p ; n ; p ; g ; p }' data2.txt

sed -n '/header/!p' data2.txt

//反转文本文件中的行,同linux命令tac(cat的反写)功能一样
sed -n '{1!G ; h ; $p }' data2.txt

echo "This, is, a, test, to, remove, commas." | sed -n '{
> :start
> s/,//1p
> /,/b start
> }'

echo "The cat sleeps in his hat." | sed 's/.at/"&"/g'
The "cat" sleeps in his "hat".

echo "The System Administrator manual" | sed '
> s/\(System\) Administrator/\1 User/'
The System User manual

echo "That furry hat is pretty" | sed 's/furry \(.at\)/\1/'
That hat is pretty


//每行后插入空白行,不包括最后一行
sed '$!G' data2.txt
sed '/^$/d ; $!G' data6.txt

//N,将下一行和当前行放在模式空间,当成“一行”;n将下一行加入当前行模式空间,但打印只显示下一行数据
sed '=' data2.txt | sed 'N; s/\n/ /'
nl data2.txt
cat -n data2.txt
1 This is the header line.
2 This is the first data line.
3 This is the second data line.
4 This is the last line.

//打印末尾行
sed -n '$p' data2.txt

//输出中只会在行间保留一个空白行
sed '/./,/^$/!d' data8.txt
//删除开头的空白行
sed '/./,$!d' data9.txt
//删除结尾的空白行
sed '{
:start
/^
\n*$/{$d; N; b start }
}'

//删除 HTML标签
sed 's/<[^>]*>//g ; /^$/d' data11.txt

gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2
gawk 'BEGIN{x=4; x= x * 2 + 3; print x}'

cat script1
BEGIN{FS=","}
{print $n}
$ gawk -f script1 n=2 data1

gawk -F: '$1 ~ /rich/{print $1,$NF}' /etc/passwd
gawk –F: '$1 !~ /rich/{print $1,$NF}' /etc/passwd
gawk -F: '$4 == 0{print $1}' /etc/passwd
gawk -F, '$1 == "data11"{print $1}' data1
gawk '{if ($1 > 20) print $1}' data4
gawk '{
> if ($1 > 20)
> {
>   x = $1 * 2
>   print x
> }
> }' data4
gawk '{
> total = 0
> for (i = 1; i < 4; i++)
> {
>    total += $i
> }
> avg = total / 3
> print "Average:",avg
> }' data5

gawk 'BEGIN{FS="\n"; RS=""} {print $1,$4}' data2
gawk 'BEGIN{FS="\n"; RS=""} {printf "%s %s\n", $1, $4}' data2

//16表示宽度
gawk 'BEGIN{FS="\n"; RS=""} {printf "%16s  %s\n", $1, $4}' data2
gawk 'BEGIN{FS="\n"; RS=""} {printf "%-16s  %s\n", $1, $4}' data2

gawk 'BEGIN{x = "testing"; print toupper(x); print length(x) }'

gawk 'BEGIN{
> date = systime()
> day = strftime("%A, %B %d, %Y", date)
> print day
> }'

很遗憾,Ubuntu Linux发行版将/bin/sh文件链接到了shell程序/bin/dash。由于dash shell只含有
原来Bourne shell中的一部分命令,这可能会(而且经常会)让有些shell脚本无法正确工作。
下一节将带你逐步了解dash shell的基础知识以及它跟bash shell的区别。如果你编写的bash
shell脚本可能要在Ubuntu环境中运行,了解这些内容就尤其重要。

由于dash的目标是简洁,因此它的环境变量比bash shell少多了。在dash shell环境中编写脚本时要记住这点。
dash shell用set命令来显示环境变量

sudo du -S /var/log/ | sort -rn

链接:https://pan.baidu.com/s/1PN-qFxEFT3AAp3fAgZ9esg

提取码:0563

赞(0) 打赏

评论 抢沙发

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏