[百晓生]-linux shell脚本攻略
By mystery
第一章:小试牛刀
#变量赋值
var = value不同于var=value
把var=value写成var = value是一个常见的错误
前者是赋值操作,后者是相等操作
#let命令可以直接执行基本的算数操作
#bc
bc是一个用于数学运算的高级工具,这个精密计算器包含了大量的选项
借助bc可以执行浮点数运算并应用一些高级函数
#重定向
>和>>并不相同,尽管这两个操作都可以将文本重定向到文件
前者先清空文件,后者会将内容追加到现有文件的末尾
#位桶(黑洞)
/dev/null是一个特殊的设备文件,这个文件接收到任何数据都会被丢弃
因此,null设备通常也被称为位桶(bit bucket)或黑洞
#tee
有一个巧妙的方法可以将数据重定向到文件
同时提供一份重定向数据的副本作为后续命令的stdin
这一切都可以使用tee来实现
tee在默认情况下会将文件覆盖,但它提供一个-a选项,可以用于追加内容
#alias
alias命令的作用只是暂时的,一旦关闭当前终端,所有设置过的别名就失效了
如果想要一直起作用,可以写入到~/.bashrc中
例:$echo 'alias cmd="commad seq"'>>~/.bashrc
#shebang的妙用
把shebang从#!/bin/bash改成#!/bin/bash -xv,这样一来,不用任何其他选项就可以用调试功能了
#读取命令序列输出
shell脚本最棒的特性之一就是可以轻松地将多个命令或工具组合下来生成输出
一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递到另一个命令,依次类推
#read
read命令提供一种不需要按回车键就可以完成输入的办法
-s不回显方式读取
-p显示提示信息
-t在特定时限内读取输入
#IFS
内部字段分隔符(Internal Field Separator)
#CSV
逗号分隔型数值(Comma Separated Value)
#for
for var in list;
do
commands;
done
#while
while condition
do
commands;
done
#算术比较
条件通常被放置在封闭的中括号内
一定要注意在[或]与操作数之间有一个空格。
如果忘记这个空格,脚本会报错
[ $var -eq 0 ] #当$var等于0时,返回真
eq 等于 | ne 不等于 | gt 大于 | lt 小于 | ge 大于或等于 | le 小于或等于
#字符串比较
使用字符串比较时,最好用双中括号,因为有时候采用单个括号会产生错误
所以最好避开它们
[ [ $str1 > $str2 ] ]; 如果str1的字母序比str2大,则返回真
[ [ -n $str1 ] ]; 如果str1包含的是空字符串,则返回真
[ [ -n $str1 ] ]; 如果str1包含的是非空字符串,则返回真
#test
test命令可以用来执行条件检测
用test有助于避免使用过多的括号(可以直接代替前面的测试条件)
第二章:命令之乐
#xargs
只要我们把find的输出作为xargs的输入,就必须将-print0与find结合使用,以字符null来分隔输出
find . -type f -name "*.txt" -print0 | xargs -0 rm -f
#tr
tr可以对来自标准输入的字符进行替换/删除/以及压缩。
它可以将一组字符变成另一组字符,因而通常也被称为转换命令(translate)
#md5sum
检验和对于编写备份脚本或系统维护脚本来说非常重要
md5sum filename > file_sum.md5
md5sum -c file_sum.md5 #这个命令会输出校验和是否匹配的消息
检验和是从文件中计算出来的。对目录计算校验和意味着我们需要对目录中的所有文件以递归的方式进行计算
#sort
-n 按数字进行排序
-r 按逆序进行排序
-M 按月份进行排序 sort -M months.txt
为了使sort的输出与以\0作为参数的终止符的xargs命令相兼容,采用下面的命令
sort -z data.txt | xargs -0 #终止符\0使得xargs命令的使用更加安全
-b 选项用于忽略文件中前导空白字符
-d 选项用于指明以字典序进行排序
sort命令只能用于由换行符分隔的记录上
#uniq
-c 选项统计各行在文件中出现的次数
sort unsorted.txt | uniq -c
#.$$
不使用tempfile命令,我们也可以使用自己的临时文件名
temp_file="/tmp/var.$$"
.$$作为添加的后缀会被扩展成当前运行脚本的进程ID
有时候也可以借助随机数
temp_file="/tmp/file_$RANDOM"
#名称.扩展名
${VAR%.*}
从$VAR中删除位于%右侧的通配符,通配符是从右向左进行匹配
%属于非贪婪操作,它从右到左打出匹配通配符的最短结果
%%属于贪婪的(greedy),这意味着它会匹配符合条件的最长的字符串
${VAR#*.}
从$VAR中删除位于#右侧的通配符,通配符从左向右进行匹配
#也有一个相对应的贪婪操作符##
VAR=hack.fun.book.txt
echo ${VAR%.*} #hack.fun.book
echo ${VAR%%.*} #hack
echo ${VAR#*.} #fun.book.txt
echo ${VAR##*.} #txt
#grep
在grep中,^标记着单词的开始,$标记着单词的结束
-q禁止产生任何输出
列出文件中以特定单词起头的所有单词
grep "^word" filepath
#echo
-e 忽略转义字符,用于交互输入自动化
第三章:以文件之名
#comm
可用于两个文件之间的比较,它有很多不错的选项可用来调整输出,以便我们执行交集/求差以及差集操作
#setuid
setuid权限允许用户以其拥有者的权限来执行可执行文件,即使这个可执行文件是由其他用户运行的
#setgid
setgid允许以同该目录拥有者所在组相同的有效权限来允许可执行文件,但是这个组和实际发起命令的用户组未必相同
#粘滞位
目录有一个特殊的权限,叫做粘滞位(sticky bit),当一个目录设置了粘滞位,只有创建该目录的用户才能删除目录中的文件,即使用户组和其他用户也有写权限,用t或T来表示,如果没有设置执行权限,但设置了粘滞位,那么用t,同时设置了执行权限和粘滞位,就用T
chmod a+t directory_name
#chattr
可以用chattr将文件设置为不可修改
一旦文件被设置为不可修改,任何用户包括超级用户都不能删除该文件,除非其不可修改的属性被移除
sudo chattr +i file
#iso
可引导光盘自身具备引导能力,也可以运行操作系统或其他软件
不可引导光盘则做不到这些
要想保留光盘的可引导性,应该将它以磁盘镜像或是ISO文件的形式进行复制
#tail
tail命令的一个重要用法是从一个内容不断增加的文件中读取数据,新增加的内容总是被添加到文件的尾部,因此当新内容被写入文件时候,可以用tail将其显示出来
tail有一个特殊的选项-f或--follow,它们会使tail密切关注文件中新添加的内容,并随着数据的增加时时保持更新
tail具有一个很有意思的特性,当某个给定进程结束之后,tail也会随之终结
#pushd
pushd和popd是基于命令行接口(CLI)的定位技术
使用pushd和popd的时候,就可以无视cd命令了
pushd /var/www
dirs
pushd +3
当涉及3个以上的目录时,可以使用pushd和popd,但是当你只涉及两个位置的时候,另一个更简便的方法:cd -
#wc
wc是一个用于统计的工具,它是Word Count的缩写,统计文件的行数/行数/字符数
统计行数-l/单词数-w/字符数-c/-L打印最长行的长度
#LOC
line of code,代码行数
#tree
tree命令是以图形化的树状结构打印文件和目录的主角
只重点标记出匹配某种样式的文件
tree path -P PATTERN | tree PATH -P "*.sh"
只重点标记出除符合某种样式之外的那些文件
tree path -I PATTERN
同时打印出文件和目录的大小
tree -h
以HTML形式输出目录树
tree PATH -H http://localhost -o out.html
将http://localhost替换为适合存放输出文件的URL,将PATH替换为主目录的真正路径
第四章:让文本飞
#grep
grep命令是UNIX中用于文本搜索的大师级工具
--color 选项可以在输出行中重点票房出匹配到的单词
如果要使用正则表达式,需要添加-E选项,或者使用egrep
-o 只输出文件中匹配到的文本部分
-v 将匹配结果进行反转
-C 只是统计匹配行的数量,并不是匹配的次数
-n 匹配字符串的行数
-b 匹配所位于的字符或字节偏移 选项-b 总是和-o 配合使用
-l 搜索多个文件并找出匹配文本位于哪一个文件中,相反的选项是-L
-R 递归搜索文件
-i 忽略大小写
-e 匹配多个样式
-f 提供一个样式文件用于读取样式
--include/exclude/exclude-dir 包括或排除文件
-Z 使用0字节后缀,-Z通常和-l结合使用
-q 静默输出
-A/-B/-C 打印出匹配文本之前或之后的行
#cut
cut是一个帮我们将文本按列进行切分的小工具。它可以指定分隔每列的定界符
在cut的术语中,每列都是一个字段
-f n 提取第n个字段
-s 避免打印出不包含定界符的行
-complement 对提取的字段进行补集运算
-d 指定字段的定界符
指定字段的字符或字节范围 -b表示字节/-c表示字符/-f表示定义字段
当用-b或-c提取多个字段时,必须使用--output-delimiter,否则,你就没法区分不同的字段了
cut range_filelds.txt -cl -3,6-9 --output-delimiter "."
#sed
sed是stream editor(流编辑器)的缩写
sed命令众所周知的一个用法是进行文本替换
-i 可以将替换结果应用于原文件
/在sed中作为定界符使用,当定界符出现在样式内部时,我们必须用前缀\对其进行转义
/pattern/d 移除匹配样式的行
&对应于之前所匹配到的单词
\(pattern\)用于匹配子串,对于匹配到的第一个子串,其对应的标记是\1
在sed表达式中使用一些变量字符串时,双绰号就有用武之地了
#awk
awk被设计用于数据流,可以对列和行进行操作,有很多内建的功能,比如数组/函数
基本结构:awk 'BEGIN{ print "start" } pattern { commands } END{ print "end" }'
当使用不带参数的print时,它会打印出当前行
关于print,需要记住两件事:
一:当print的参数是以逗号进行分隔时,参数打印时则以空格作为定界符
二:在awk的print语句中,双引号是被当做拼接操作符使用的
特殊变量:
NR:number of records,记录数量,对应于当前行号
NF:number of fields,字段数量,对应于当前字段数
$0:这个变量包含执行过程中当前行的文本内容
$1:这个变量包含第一个字段的文本内容
$2:这个变量包含第二个字段的文本内容
print $NF 打印一行中最后一个字段
-v 可以将外部值传递给awk
如果只想读取某一行,可以使用getline函数
-F "delimiter" 明确指定一个定界符
将command的输出读入变量output
"command" | getline output;
#paste
cat命令所实现的拼接通常是按照行来进行的
paste命令实现同按列来拼接
-d 明确指定定界符
#rev
检查一个字符串是否是回文的最简单的方法就是使用rev命令
rev命令接受一个文件或stdin作为输入,并逆序打印出每一行内容
tac命令将所有的行进行反转
#context line
前后行