读《Linux Shell脚本攻略》第1章笔记

  • A+
Categories:Shell

1. #!、shebang意义
Linux环境中的任何脚本语言,都是以这样一个被称为shebang的特殊行作为起始的,在这行中,字符#!被置于解释器路径之前。/bin/bash是解释器的位置

http://zh.wikipedia.org/wiki/Shebang

2. echo、printf
echo 后面不用引号,用双引号,单引号区别,并总结双引号中需要转义(\)的特殊字符
printf使用引用文本或由空格分隔的参数,我们可以在printf中使用格式化字符串。我们还可以指定字符串的宽度、左右对齐方式等。在默认情况下,printf并不像echo命令一样会自动添加换行符,我们必须在需要的时候手动添加,比如在下面的脚本中:
#!/bin/bash
printf “%-5s %-10s %-4s\n” No Name Mark
printf “%-5s %-10s %-4.2f\n” 1 Sarath 80.3456
printf “%-5s %-10s %-4.2f\n” 2 James 90.9989
printf “%-5s %-10s %-4.2f\n” 3 Jeff 77.564
输出结果:
No    Name       Mark
1     Sarath     80.35
2     James      91.00
3     Jeff       77.56
%s、%c、%d、%f都是格式化字符,其所对应的参数可以置于带引号的格式化字符串之后。
%-5s格式化为左对齐宽度为5的字符串替代(-表示左对齐),如果不用-指定对齐方式,字符串则采用右对齐形式。宽度指定了保留给某个变量的字符数,列
和列本身有一个空字符串。对Name而言,保留宽度为10,所以看起来列和列之间有11个字符串。因此,任何Name字段的内容都会被显示在10字符宽的
保留区域内,如果内容不足10字符,余下的则会以空格符填充。如果超过10个字符,列对齐效果将被打乱。
%-4.2,其中.2指定保留2个小数位,对小数部分四舍五入。注意,在每行格式字符串后都有一个换行符\n。

3. 颜色输出
打印彩色文本对应颜色码:重置=0,黑色=30,红色=31,绿色=32,黄色=33,蓝色=34,洋红=35,青色=36,白色=37
打印彩色背景对应颜色码:重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47
echo -e “\e[1;31mThis is red text\e[0m"
echo -e "\e[1;42mGreen background\e[0m"

4. cat /proc/`pgrep java`/environ | tr '\0' '\n'
tr '\0' '\n' 重新格式化输出,将\0(null字符)替换成\n(换行)

5. bc
设定小数精度:scale=2 将小数位个数设置为2.
echo "scale=2;3/8" | bc
.37

进制转换:
echo "obase=2;100" | bc
1100100 #十进制转换成二进制
echo "obase=10;ibase=2;1100100" | bc
100 #二进制转换成十进制

计算平方以及平方根:
echo "sqrt(100)" | bc
10
echo "10^10" | bc
10000000000

6. stdin、stdout、stder、tee
0 - stdin(标准输入)
1 - stdout (标准输出)
2 - stderr (标准错误)

$echo a1 > a1;cp a1 a2;cp a2 a3 ;chmod 000 a1
$ cat * | tee -a out.txt | cat -n
cat: a1: Permission denied
1  a1
2  a1
$ cat out.txt
a1
a1

tee命令接收到来自stdin的数据。它将stdout的一份副本写入文件out.txt。同时将另一份副本作为后续命令的stdin。命令cat -n将从stdin中接收到的每一行数据前加上行号并写入stdout。-a参数可以用于追加内容
可以使用stdin作为命令参数,只需要将-作为命令的文件名参数即可:
$ echo who is this | tee -
who is this
who is this

7. 自定义文件描述符
文件描述符是用于访问文件的一个抽象指针。存取文件离不开被称为“文件描述符”的特殊数字。0、1和2分别是stdin、stdout和stderr的预留描述符。
我们可以使用exec命令创建自定义的文件描述符。3中模式:只读模式;截断模式;追加模式
为读取文件创建一个文件描述符:
# touch input.txt
# exec 3<input.txt  #使用文件描述符3打开并读取文件
# echo This is a test line > input.txt
# exec 3<input.txt
# cat <&3
This is a test line
如果要再次读取,我们就不能再继续使用文件描述符3了,而是需要用exec重新分配文件描述符3以便用于读取。

创建一个文件描述符用户写入(截断模式):
# exec 4>output.txt #打开文件用于写入
# echo newline >&4
# cat output.txt
newline

创建一个文件描述符用于写入(追加模式):
# exec 5>>input.txt
# echo appended line >&5
# cat input.txt
This is a test line
appended line

8. 数组和关联数组
bash同时支持普通数组和关联数组。普通数组只能使用整数作为数组索引,而关联数组可以使用字符串作为数组索引。关联数组是从bash4.0开始被引入。
定义关联数组
首先需要使用单独的声明语句将一个变量名声明为关联数组。声明语句如下:
# declare -A ass_array
声明之后,可以用两种方法将元素添加到关联数组中。
1). 利用内嵌索引值列表法,提供一个索引值列表:
# ass_array=([index1]=val1 [index2]=val2)
2). 使用独立的索引值进行赋值:
# ass_array[index1]=val1
# ass_array[index2]=val2

列出数组索引
每一个数组元素都有一个索引用于查找。普通数组和关联数组具有不同的索引类型

9. 获取终端信息
获取终端的行数和列数:
tput cols
tput lines

打印出当前终端名:
tput longname

将光标移动到方位(100,100)处:
tput cup 100 100

设置终端背景色:
tput setb no #no取值在0~7之间

将文本前景色设置为白色:
tput serf no #no取值在0~7之间

设置文本样式为粗体:
tput bold

删除当前光标位置到行尾的所有内容:
tput ed

在输入密码的时候,不能让输入的内容显示出来,在下面的例子中,我们将看到如何使用stty来实现这个要求:
#!/bin/bash
#Filename:password.sh
echo -e “Enter password: ”
stty -echo
read password
stty echo
echo
echo $password
echo Password read.
其中,选项-echo禁止将输出发送到终端,而选项echo则允许发送输出。

用tput和sleep从0开始计数到40:
#!/bin/bash
#Filename sleep.sh
echo -n Count:
tput sc

count=0;
while true;
do
if [ $count -lt 40 ];
then let count++;
sleep 1;
tput rc
tput ed
echo -n $count;
else exit 0;
fi
done
在上面的例子中,变量count初始化为0,随后每循环一次便增加1。echo语句打印出count的值。我们用tput
sc储存光标位置。在每次循环中,我们通过恢复之前储存的光标位置,在终端中打印出新的count值。恢复光标位置的命令是tput rc。tput
ed清除从当前光标位置到行尾之间的所有内容,使得旧的count值可以被清除并写入新值。循环内的1s延时是通过sleep命令来实现的。

10. 调试shell脚本
set -x:在执行时显示参数和命令。
set +x:禁止调试。
set -v:当命令进行读取时显示输入。
set +v:禁止打印输入。

11. Fork炸弹
: () {
: | : &
}; :
: 是函数名,执行一个调用自己的递归并且 pipe 到自己,& 表示后台执行程序,最后的一个 : 是在函数外调用和执行 : () 这个函数的意思

12. read
参数可以组合使用
# read -n 2 var   读取2个字符并存入变量var
# echo $var

# read -s var  #用不回显的方式读取密码
# echo $var

# read -p “Enter input:” var    #显示提示信息

# read -t 2 var    #在2s内将输入的字符串存入到变量var

# read -d “:” var    #使用:作为定界符结束输入行

13. 字段分隔符和迭代器
内部字段分隔符(Internal Field Separator, IFS)
# cat ifs.sh
#!/bin/bash
data=”name,sex,rollno,location”
oldIFS=$IFS
IFS=”,”
for item in $data;
do
echo Item:$item
done
IFS=$oldIFS
结果如下:
Item:name
Item:sex
Item:rollno
Item:location

IFS的默认值为空白符(换行符、制表符或者空格)。
当IFS被设置为逗号时,shell将逗号解释成一个定界符,因此变量$item在每次迭代中读取由逗号分隔的字串作为变量值。
如果没有把IFS设置成”,”,那么上面的脚本将会全部数据作为单个字符串打印出来。

14. Bash多种类型的循环
for 循环
while 循环
until 循环
&&逻辑与运算符   ||逻辑或运算符

15. 算术比较
条件通常被放置在封闭的中括号内。一定要注意在[]与操作数之间有一个空格。
-gt:大于
-lt:小于
-ge:大于或等于
-le:小于或等于
-eq:等于
-ne:不等于

可以结合 -a 逻辑与 -o 逻辑或条件进行测试

文件系统相关属性测试:
[ -f $file_var ]    如果给定的变量包含正常的文件路径或文件名,则返回真
[ -x $var ]    如果给定的变量包含的文件可执行,则返回真
[ -d $var ]    如果给定的变量包含的是目录,则返回真
[ -e $var ]    如果给定的变量包含的文件存在,则返回真
[ -c $var ]    如果给定的变量包含的是一个字符设备文件的路径,则返回真
[ -b $var ]    如果给定的变量包含的是一个块设备文件的路径,则返回真
[ -w $var ]    如果给定的变量包含的文件可写,则返回真
[ -r $var ]    如果给定的变量包含的文件可读,则返回真
[ -L $var ]    如果给定的变量包含的是一个符号链接,则返回真

字符串比较:
使用字符串比较是,最好用双中括号,因为有时候采用单个中括号会产生错误,所以最好避开他们。
[[ $str1 = $str2 ]]    当str1等于str2时,返回真。str1和str2包含的文本是一模一样
[[ $str1 == $str2 ]]    这是检查字符串是否相等的另一种写法。也可以检查两个字符串是否不同
[[ $str1 != $str2 ]]    如果str1和str2不相同,则返回真
[[ $str1 > $str2 ]]    如果str1的字母序比str2大,则返回真
[[ $str1 < $str2 ]]    如果str1的字母序比str2小,则返回真
[[ -z $str1 ]]    如果str1包含的是空字符串,则返回真
[[ -n $str1 ]]    如果str1包含的是非空字符串,则返回真
注意:在=前后各有一个空格,如果忘记加空格,那就不是比较关系了,而变成了赋值语句

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: