在此首先声明,本笔记是在学习Sarath Lakshman的书同时记录,向作者和译者表示感谢。
1.2终端打印
echo "hello";echo 'hello';echo hello的效果是一样的,要打印!则只能用echo hello !(书上说可以用转义字符\,试过后发现打出来的是\!)。字符串用双引号,单引号以及裸的各有副作用:(1)使用不带引号的echo,无法在显示文本中使用分号;(2)使用单引号时,不会对其中的变量求值,如$var;(3)不带引号呢,咳,可以打出!的。
打印还可以使用printf,与C语言中的使用是一样的,但是不会像echo一样自动添加换行符。
printf "%-5s %-10s %-4.2f\n" 1 Jason 90.3443,其中-表述左对齐,数字表示宽度,4.2中的.2表示小数的位数。
可以使用-n标志忽略echo结尾的换行符,使用-e说明含有转义序列如echo -e "1\t2\t3"
echo -e "\e[1;31m This is red text \e[0m"打印红色字符,echo -e "\e[1;42m This is red text \e[0m"打印绿色背景。shell脚本中颜色定义是:
字体:重置:0 黑色=30 红色=31 绿色=32 黄色=33 蓝色=34 洋红=35 青色=36 白色=37
背景:重置:0 黑色=40 往后类推
1.3玩转变量和环境变量
脚本语言通常不需要在使用变量前声明其类型(python如此),只要直接赋值就可以。一些特殊的变量会被shell环境和操作系统环境用来存储一些特别的值,这类变量就叫做环境变量。
使用env命令可以查看所有与此终端进程相关的环境变量,查看每个进程运行时的环境变量可以使用cat /proc/$PID/environ,其中PID为相关进程的进程ID,可用pgrep xxx获取。
环境变量输出时使用null字符(\0)分割,可以用tr命令将其替换为'\n':tr '\0' '\n'。
变量赋值方式:var=value,value不包含任何空白字符。 var = value是常见错误,前者是赋值操作,后者则是相等操作。加上$或者${}就可以打印变量,也可以在printf或echo的双引号中引用变量值。
补充内容:
(1)获得字符串长度,length=${#var}
(2)识别shell版本,echo $SHELL 或echo $0
(3)检查是否为超级用户,
if [ $UID -ne 0 ];then
> echo Non root user.Please run as root.
> else
> echo "Root user"
> fi
直接在shell里敲就可以了。。。或者写成一个脚本文件
(4)可以使用PS1环境变量定制提示文本,并且\u,\h,\w扩展为用户名,主机名和当前工作目录
1.4通过shell进行数学运算
let (()) []执行基本的算术操作。高级工具比如expr和bc。
let可以直接执行基本的算术操作,使用时变量名之前不需要再添加$.
[]与let类似,result=$[no1 + $no2],在[]中也可以使用$
(())变量名前需要加$,好吧,看起来很乱么,用一种就好了
expr表达式的意思,result=`expr 3 + 4`或result=$(expr $no1 + 5);
以上只能执行整数运算。
bc的功能很强大,可以做复杂的浮点计算,如echo "4 * 0.26" | bc
echo "scale=2;3/8" | bc 设定小数位数
no=1100100
echo "obase=10;ibase=2;$no" | bc 是进制转换
echo "sqrt(100)" | bc 开方运算
1.5文件描述符和重定向
0-stdin(标准输入) 1-stdout(标准输出) 2-stderr(标准错误)
>先清空,再写入内容;>>追加内容;等同于1>或1>>,即输出重定向
tee命令接收来自stdin的数据,终端打印同时重定向到文件。
使用-作为命令行参数以代替stdin.
输入重定向则用< 和<<
cat和EOF结合可以输出文本块(EOF只是一个标志,可以用任意的)
使用exec自定义文件描述符:
echo this is a test line > input.txt
exec 3<input.txt
cat <&3
关于自定义文件描述符总结:首先要exec指定一个描述符,然后紧接着用<>或<<>>表示描述符的方式。
调用的时候输入则用<$3,输出则用>&3.
1.6数组和关联数组
数组定义:array_var={1 2 3 4 5};或者array_var[0]="test1"。。。类推
打印特定索引的数组元素内容:echo ${aray_var[0]}
打印数组所有值:echo ${array_var[*]},*可用@代替
打印数组长度(数组中元素的个数):echo ${#array_var[*]}
补充关联数组(这不是类似python中的字典吗?):
(1)首先要将一个变量声明为关联数组:declare -A ass_array
然后可以用内嵌索引-值或者索引-值列表对数组赋值。
(2)列出数组索引:
echo ${!array_var[*]}注意和普通数组的区别,有个“!”表述列出索引列表,没有"!"列出值列表。
1.7使用别名
alias ls='echo hello world'。在不受信任的环境下在命令前要加上/.
1.8获取终端信息
tput cols;tput lines;打印当前终端的列数和行数。
密码不回显:
1 #!/bin/bash
2 #filename:password.sh
3 echo -e "Enter password:"
4 stty -echo
5 read password
6 stty echo
7 echo
8 echo Password read.
1.9获取、设置日期和延时
date;date +%s纪元时
date -s "日期字符串"
sleep命令设置延时
1.10调试脚本
set -x:在执行时显示参数和命令;
set +x:禁止调试;
set -v:当命令进行读取时显示输入;
set +v:禁止打印输入
还可以从脚本文件第一行:改成#!/bin/bash -xv
对于自定义格式调试信息,可以使用_DEBUG环境变量。
1 #!/bin/bash
2 function DEBUG()
3 {
4 [ "$_DEBUG" == "on" ] && $@ || :
5 }
6 for i in {1..10}
7 do
8 DEBUG echo $i
9 done
1.11函数和参数
上面貌似用到函数了
$1是第一个参数,$n是第n个参数;
$@被扩展成"$1""$2".."$n"
补充内容:
(1)递归函数:
典型的即使fork炸弹:“:(){:|:&};:”可通过修改配置文件/etc/security/limits.conf来限制可生成的最大进程数来避开这枚炸弹。ulimit -Hu 30也可以限制进程数。
(2)导出函数:export -f fname,函数的作用域可以扩展到子进程
(3)读取命令返回值echo $?
(4)多种向命令传递参数的方式,不一一列举了
1.12读取命令序列输出
用管道“|”连接多个命令;
利用子shell生成一个独立的进程,用()操作符来定义一个子shell;用子shell或反引用的方法将命令的输出读入一个变量中,书上说放如双引号中可以保留空格和换行符,直接用echo可以保留,但是如果给变量赋值,结果就没有保留换行符了。
1.13以不按回车键的方式读取字符“n”
读取n个字符存入变量:read -n 2 var
用不回显的方式读取密码:read -s var
显示提示信息:read -p "Enter input" var
在特定时限内读取输入:read -t 2 var
用定界符读取输入行:read -d ":" var
1.14字段分隔符和迭代器
IFS=“,“分隔由逗号分隔的字段。
IFS结合循环可以变得相当强大。
for var in list;
do
commands;
done
list可以是一个字符串,也可以是一个序列。
1.15比较与测试
(1)算术比较:
-gt:大于 -lt:小于 -ge:大于或等于 -le:小于或等于
(2)文件系统相关测试:
[ -f $file_var ]:如果给定的变量包含正常的文件路径或文件名,则返回真。
[ -x $var ]:如果给定的变量包含的文件可执行,则返回真。
[ -d $var ]:如果给定的变量包含的是目录,则返回真。
[ -e $var ]:如果给定的变量包含的文件存在,则返回真。
[ -c $var ]:如果给定的变量包含的是一个字符设备文件的路径,则返回真。
[ -b $var ]:如果给定的变量包含的是一个块设备文件的路径,则返回真。
[ -w $var ]:如果给定的变量包含的文件可写,则返回真。
[ -r $var ]:如果给定的变量包含的文件可读,则返回真。
[-L $var ]:如果给定的变量包含的是一个符号链接,则返回真。
(3)字符串比较:要用两个[]
[[ $str1 = $str2]]:
[[ -z $str1 ]]:如果是空字符串,则返回真。
[[ -n $str2 ]]:如果是非空字符串,则返回真。