最近计划较规律的再学习次shell,之前总是反反复复零零碎碎的学习,实际使用时效率和质量都不好,心里很虚。
刚好去新公司前的这个月时间里,可以好好安排下。我的计划是针对着《linux shell脚本攻略》这本书进行学习,这本书似乎比较偏实际运用,并不是很系统,不过我觉得可能刚好适合我,我现在就需要实际的练习,遇到相关的问题再去查阅更系统的知识吧。
计划针对每章做一个笔记,当然可能会根据内容做调整。今天附上第一章的学习笔记。
=================================================================(以下笔记)
1,脚本的运行
1.1,脚本起始行的#!叫做shebang
1.2,运行脚本,
a, 脚本可执行时,如 ./脚本;
b, 脚本没执行权限时,用bash来调用,如 bash 脚本;
另,shebang的作用是告诉使用#!后指定的shell,而不是使用默认的shell
2,打印内容
2.1,echo打印
a, echo “asd dfg”;
b, echo asd dfg;
c, echo ‘asd dfg’,
结果都是打印出asd dfg
区别:””双引号,会解释里面的内容,如$name、!等,不过可用\来转义;
‘’单引号,里面的内容都以文本输出;
echo he;he,分号会起作用,后面的he会作为单独的命令;而echo “he;he”则打印整个字符串;
echo –n 忽略结尾换行符
echo –e enable interpretation of backslashescapes,解释反斜杠,如echo –e “1\t2\t3”结果为123
2.2,printf打印,
printf需手动加换行(echo自动加)
直接看例子:printf “%-5s %-10s %-4s\n” No namemark,参数解释如下
-表示左对齐
5表示宽度为5(不够5补0,超过5不截断)
%s %d %f等为格式替换符(分别对应字符串、数字、浮点数)
3,shell中的变量
3.1,env看当前终端所有进程的环境变量;
cat /proc/PID/environ看某进程的环境变量;
pgrep 进程,得到进程的PID
export设置环境变量
常见环境变量 HOME PWD UESR UID SHELL
识别当前shell,echo $SHELL 或 echo $0,因为此时arg0就是当前shell
Bash提示字符串,由.bashrc中的PS1决定
3.2,变量赋值:var=value,(不能有空格!var = value是相等比较操作)
打印变量:echo $var 或echo ${var} (而echo $(var)是运行var语句)
变量长度:len=${#var}
4,计算
五种方式,let、(( ))、[ ]、expr、bc
let:let中变量前不用加$,如let result=no1+no2; let no1++; let no1+=6等
(( )):result=$((no1 + 40))或result=$(($no1 + 40))
[]:result=$[no1 + 40]或result=$[$no1 + 40]注:[ ]和(( ))相似
高级expr,简单的例子result=$(expr $no1 + 5),加号那里要有空格!
高级bc,简单的例子echo “4*0.4” | bc;
bc中有obase和ibase表示输入和输出的进制;
bc可以计算浮点数
5,文件描述符和重定向
a,重定向默认使用标准输出,如ls ss > out.txt,即ls ss的stdout重定向到out中;
在>或>>前加描述符,可修改上面方式,如ls ss 2>out.txt,即stderr重定向到out中;
b,stderr和stdout放到同一个文件中的方法,
cmd >out 2>out,stderr和stdout会交叉写入out,次序混乱
cmd >out 2>&1,把stderr重定向到stdout(反之,1>&2似乎不对)
cmd &> out,这个也可以,把stdout和stderr重定向到out
c,tee的用法,如cat a* | tee out | cat –n,
注1,tee只能从stdout中进行读取(out中只有stdout,没有stderr);
注2,tee将重定向数据的副本是作为后续命令(cat)的stdin
其他:cat –n,每一行加行号;grep –n,输出行号(文本原来的行号)
tee –a out追加到out中,相等与>>,而不是>
d,stdin等同于’-’等同于/dec/stdin
stdout等同于/dev/stdout
stderr等同于/dec/stdout
e,文件重定向到命令:
grep a << aa.c,
等价于grep a aa.c 和 cat aa.c | grep a
f,cat > test2 < test1,把test1的内容输出给test2
g,cat <<EOF asd #表示以EOF(其它字符串都可以,文件分界符,或用ctrl+d)为终止标志
cmd......
EOF #再次输入EOF时终止,这样可以一次性输入多行内容
h,exec,用于将文件关联到自定义的fd上,具体例子再看书吧
6,数组
分普通数组+关联数组
a,普通数组
普通数组定义:array=(12 3) 小括号;
或array[0] = “1” …
输出数组元素:echo ${array[0]},一定要有大括号;
echo ${array[*]}或echo${array[@]}列出所有元素
输出长度:echo ${#array[*]}(如果0 1 3位置上有元素,2位置为空,长度将为3)
b,关联数组
关联数组,需要先声明一个变量名为关联数组!
declare –A ass_array(-a声明普通数组,-A声明关联数组)
然后添加元素:ass_array=([apple]=”12”[orr]=”15”) 或 ass_arry[aaa]=”17”
列出数组索引:echo ${!ass_array[*]}或echo ${!ass_array[@]},关键用!号(普通数组也适用)
7,别名
别名alias(为了别名一直有效,可放进.bashrc脚本中)
删除别名unalias
另:在别名前加”\”进行转义,此时将执行原本的命令,如\l将不再是(alias l='ls -CF')了
8,终端相关命令
介绍了 tput stty
tput, reset - initialize a terminal orquery terminfo database
stty - change and print terminal linesettings
如,输入密码时,不让输入内容显示出来:stty –echo; read password; sty echo(也可以用read –s)
9,时间相关命令
date:
date 输出Fri Jan 2 02:23:10 UTC 1970
date +%s 输出1435210675
date --date “Fri Jan 2 02:23:10 UTC 1970” +%s --date用于提供日期串输入,后面为转换后的输出格式
常用格式%a %A(sat Saturday)
%d (31日)
%b %B(Nov November)
%y%Y(15 2015) %D(06/24/15)月日年
%H %M %S %N %s è 小时 分钟秒 纳秒 纪元时
date –s ”时间串”:设置时间
sleep
sleep 5睡眠5秒
另:time:run programs and summarize systemresource usage测跑一个程序花费的时间
timeout:run a command with a time limit
10,调试脚本
bash –x 脚本,-x标识将脚本中执行的每一行代码输出到stdout
bash –n脚本,不执行,仅查询语法问题
bash –v脚本,执行脚本前,先打印脚本内容
在脚本内set –x 显示参数和命令;set +x禁止调试;
set –v读取时显示输入;set +v禁止打印输入(类似read –s)
另一种方式:定义一个函数如function DEBUG( )来执行某段代码,并加上自定义的调试信息
其他:
:冒号,告诉shell不做任何操作;
#!/bin/bash可改为#!/bin/bash –xv
11, 函数和参数
定义函数: functionfname()
{}
或
fname()
{}
使用函数:fname arg1arg2
参数:$1 …$n:第n个参数
$@:”$1” “$2”…所有参数(比$*用的更多)
$*:”$1c$2c…”所有参数,但为一个字符串整体,c为IFS的第一个字符
导出函数:export –f fname
获取函数(进程也一样)的返回值(funciton中return的值):echo $?
12,多个命令序列
cmd1 | cmd2 | cmd3
子shell:$(cmd) 或 `cmd` 或( cmd1; cmd2)
“子shell”,使用双引号可以保留空格和换行符(怎么实验结果不对啊......)
13,读取数据 read
read –n 4 var:最多读n=4个字符
read –s var:不显示输入
read –p “asd” var:提示
read –t 3 var:3秒时间限制
read –d “:” var:定界符改为冒号(只能取一个字符,如”34”,定界符为3)
14,IFS字段分隔符(internal field separator)
IFS默认为空白字符(\n \t 和 空格)
15,循环
for var in list (list可以用 {1..50} {a..z} {h..a} $(seq 1 3)来生成,seq只生成数字序列)
do
cmd
done
for (( ; ;)) 如for((i=1; i<10;I=i+1)) 要两个小括号
do
cmd
done
while condtion
do
cmd
done
until condition
do
cmd
done
16,判断和比较
16.1 比较语句
a,if比较语句
if condition; then
cmd1
elif condition; then
cmd2
else
cmd3
fi
b,简单比较语句(用[ ],左右两边需要空格分隔)
[ condition ] && action
[ condition ] || action
16.2 比较类型:算法比较、字符串比较、文件属性比较
算法比较,如[ $var –eq0 ],
-eq 等于;-ne 不等于
-gt大于; -lt 小于;
-ge 大于等于; -le 小于等于
字符串比较,如[ $str == $str2 ],
==、= 相等比较
!= 不等比较
> < 大小比较
-z 是否为空字符串
-n 是否为非空字符串
注:比较字符串,中括号内的常数,最好用’’或””包含;变量,最好用””包含;
或者用[[ ]]来包含字符串比较(效果同用””)
文件属性比较,如[ -f $file_name ],
-f 是否存在该路径名或文件名
-x 是否可执行
-d 是否为目录
-e 是否存在,exist
-c 是否字符设备 –b是否块设备
-w 是否可写
–r 是否可读
-L是否为符号连接
另:1,并、或操作,-a –o放在[ ]里;&& || 放在[ ]外面
2,test等同于[ ],如[ $var –eq 0 ] 等同于 test $var –eq 0