天天看点

《linux Shell 脚本攻略》进阶学习(第一部分)

第二章命令之乐

cat 不仅可以读取文件并且连接数据,它还能从标准输入中进行读取

要从标准输入中读取,就要使用管道操作符 

echo 'Text through stdin' | cat - file.txt。这里的-被作为来之stdin 文本的文件名称

实例 在file.txt 中写入dfagfmirgjriogjrogijdfgio后

$ echo 'Text through stdin' | cat - file.txt

Text through stdin

dfagfmirgjriogjrogijdfgio

$ echo 'Text through stdin' | cat < file.txt

$ echo 'Text through stdin' | cat  file.txt

cat补充内容

 -s, --squeeze-blank #压缩连续的空白行

             suppress repeated empty output lines

tr

 -s, --squeeze-repeats#将多个连续的字符压缩成单个字符

             replace each input sequence of a repeated  character  that  is

             listed in SET1 with a single occurrence of that character

如:file.txt 内容

line

$ cat file.txt | tr -s '\n'

cat -n stream

      -n, --number #给内容之前加上行号

             number all output lines

录制与回放终端回话,很实用

开始录制回话

$ script -t 2>time.log -a output.session

Script started, file is output.session

type commend

.....

exit

两个配置文件被同时当做script命令的参数。其中一个文件(timing.log)用于存储时序信息,描述每一个命令在何时运行,另一个文件(output.session)用于存储命令输出,-t选项用于将时序数据导入stderr。2>则用于将stderr重定向到timeing.log。

$ scriptreplay time.log output.session 

find文件查找

-print 文件跟文件夹会以\n分隔

find sourcedOf -iname "example" -print(忽略字母大小写)

匹配多个

find \( -name "*".txt -o -name  "*.pdf" \) -print

否定参数 !

find . ! -name "*.txt" -print 不以.txt 结尾的

-exec 结合多个命令

-exec ./command.sh {} \;

-exec printf "text file: %s\n" {} \;

$ find . -exec printf "text file is: %s\n" {} \;

text file is: .

text file is: ./file.txt

text file is: ./time.log

text file is: ./output.session

玩转xargs

xargs 也可以将单行或多行文本输入转换成其他格式,例如单行变多行或是多行变单行

bash黑客都喜欢单行命令

command | xargs

xargs 是一种替换方式,类似与find命令的-exec参数

实战演练

1.将多行输入装换成单行输出

cat file.txt | xargs 

line line line line line line line line

2.将单行输入装换成多行输出

指定每行最大值 -n max,每行max个参数,每个参数都是由" " 空格隔开的字符串。空格是默认的定界符

cat file.txt | xargs -n 3

line line line

line line

更多xargs使用baidu 

使用tr进行转换

tr 可以进行替换,删除,压缩

tr 只能通过stdin,而无法通过命令行参数来接受输入。他的调用格式如下

tr [options] set1 set2

echo "Hello who IS ThIs" | tr 'A-M,n-z' 'a-m,N-Z'

hellO WhO iS ThiS

使用tr删除字符

tr -d 'set1' #只使用set1 ,而不使用set2

echo "hello 0980world" | tr -d '0-9'

hello world

字符集的补集

tr -c [set1] [set2] 

 -c, -C, --complement 补数

             use the complement of SET1

zhangjianlin@zhangjianlin:~/mytest/linuxtest/linuxshellscrill/second$ echo -e  "hello 0980world" | tr -d -c '0-9 \n'

0980

zhangjianlin@zhangjianlin:~/mytest/linuxtest/linuxshellscrill/second$ echo -e  "hello 0980world" | tr -d -c '0-9'

算数运算

echo {1..50} | echo $[ $( tr ' ' '+' ) 0 ] 

1725

$[ operation ] 执行算术运算

相当于$[ 1+...+50+0 ]

文件名的处理

$name ${name%$1}$2  #${name%\.*} "%"号除去后缀名,只取文件名

${file_name#*.} 只留扩展名或后缀

校验和核实

校验对与编写备份脚本或系统维护脚本来说都非常重要

最知名且最为广泛的校验和技术是md5sum和shalsum

计算md5sum,使用下面命令

md5sum filename 

$ md5sum file.txt 

221950d53cb7cc10da1c3e7e7ec4e0d5  file.txt

$ md5sum file.txt > file.md5

$ md5sum -c file.md5 

file.txt: 确定

sha1sum 跟 md5sum类似

对目录进行校验

校验和是从文件中计算得来的。对目录计算校验和意味着我们需要对目录中的所有文件以递归的方式进行计算

它可以使用命令md5deep或sha1deep来实现

md5deep -rl directory_path >directory.md5

#-r 使用递归的方式

#-l 使用相对路径。默认md5会输出文件的绝对路径 

用下面命令进行核实

$ md5sum -c directory.md5

批量重命名和移动批量重命名文件名称(包括后缀名)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

<code>#a!/bin/bash</code>

<code>functionlistfiles(){</code>

<code>forfilein*; </code><code># * is all of pwd'files</code>

<code>do</code>

<code>echo</code><code>$</code><code>file</code>

<code>done</code>

<code>}</code>

<code>functioninputRule(){</code>

<code>read</code><code>-p </code><code>"please input the fromsuffix as *.txt:"</code><code>fromsuffix;</code>

<code>read</code><code>-p </code><code>"please input the tosuffix as .txt:"</code><code>tosuffix;</code>

<code>read</code><code>-p </code><code>"please input the part of file name:"</code><code>headname;</code>

<code>functionchangename(){</code>

<code>count=1;</code>

<code>forfromname </code><code>in</code><code>$fromsuffix;</code>

<code>new=</code><code>"${headname}${count}${tosuffix}"</code>

<code>mv</code><code>"$fromname"</code><code>"$new"</code><code>2&gt; </code><code>/dev/null</code><code>;</code>

<code>if</code><code>[ $? -eq0 ];</code>

<code>then</code>

<code>echo</code><code>"Renameing $fromname to $new"</code><code>;</code>

<code>letcount++</code>

<code>fi</code>

<code>inputRule;</code>

<code>changename;</code>

<code>#listfiles;</code>

批量更改名称后缀,不包含名称

<code>#!/bin/bash</code>

<code>functioninputDialog(){</code>

<code>read</code><code>-p </code><code>"input fromsuffix:"</code><code>fromsuffix</code>

<code>read</code><code>-p </code><code>"input tosuffix:"</code><code>tosuffix</code>

<code>functionchangeSuffix(){</code>

<code>forfromname </code><code>in</code><code>*${fromsuffix};</code>

<code>#echo $fromname \n</code>

<code>#echo ${fromname%$fromsuffix}$tosuffix</code>

<code>mv</code><code>"$fromname"</code><code>"${fromname%$fromsuffix}$tosuffix"</code><code>#不加""mv: 目标"*.png" 不是目录</code>

<code>echo</code><code>"$fromname"</code><code>rename to </code><code>"${fromname%$fromsuffix}$tosuffix"</code>

<code>inputDialog;</code>

<code>changeSuffix;</code>

echo -e "\e[1;42m Green Background \e[0m"  彩色背景打印

echo $var 或 echo ${var}

var=value 一个赋值

var = value 一个相等操作

赋值时双引号的使用(value是否包含空格)

若无空格,特殊字符,加不加无所谓

如:var=value 或 var="value"

但var="value cat" 必须加""

length=${#var}获取变量值的长度

如:

zhangjianlin@zhangjianlin:~$ echo ${#PATH}

288

zhangjianlin@zhangjianlin:~/mytest/linuxtest/linuxshell$ echo "4 * 0.56" | bc

2.24

数组

array_var=(1212 1233 424 565)

#!/bin/bash

array_var=(1212 3434 546 7687)

echo ${array_var[*]} {}命令块,能执行命令,处理特殊字符

echo ${#array_var[*]} #4

<code>array_var=(1212 3434 546 7687)</code>

<code>echo</code> <code>${array_var[*]}</code>

<code>echo</code> <code>${</code><code>#array_var[*]}</code>

alias rmback='cp $@ ~/backup; rm $@' 删除时备份

终端工具

tput和stty是两款终端处理工具

tput cols,lines,longname,cpu 100 100,

输入密码时,不能让输入的内容显示出来。用stty

<code>#Filename:password.sh</code>

<code>function</code> <code>enterpassword(){</code>

<code>echo</code> <code>-e </code><code>"Enter password"</code>

<code>stty -</code><code>echo</code>

<code>read</code> <code>password</code>

<code>stty </code><code>echo</code>

<code>echo</code> <code>password </code><code>read</code>

<code>enterpassword</code>

在脚本中生成延时

<code>#Filename: sleep.sh</code>

<code>function</code> <code>delaytime(){</code>

<code>echo</code> <code>-n Count:</code>

<code>tput sc </code><code>#store cursor</code>

<code>count=0;</code>

<code>while</code> <code>true</code><code>;</code>

<code>if</code> <code>[ $count -lt 40 ];</code>

<code>then</code> <code>let</code> <code>count++;</code>

<code>sleep</code> <code>1;</code>

<code>tput rc </code><code>#recover cursor</code>

<code>tput ed </code><code>#clear the content from the head to tail of cursor</code>

<code>echo</code> <code>-n $count;</code>

<code>else</code> <code>exit</code> <code>0;</code>

<code>delaytime;</code>

递归函数

bash同样支持递归函数

F(){echo $1;F hello;sleep 1;}

Fork炸弹":(){ :|:&amp; };:"这个递归能调用自身,不断产生新的进程 :勿用

利用子shell 生成一个独立进程

pwd

(cd /bin; ls);

通过引用子shell的方式保留空格和换行符

假设我们使用子shell或反引号的方法将命令的输出读入一个变量中,可以将它放入双引号中,以保留空格和换行符(\n)

out="$(cat text.txt)" 保留空格跟换行符号

out=$(cat text.txt)

用不回显的方式读取密码read

read -s var

在特定时限内读取输入

read -t 2 var

read -t 2 -s var

使用定界符结束输入,不使用Enter结束输入

read -d ":" var  达到能输入换行的母的

zhangjianlin@zhangjianlin:~/mytest/linuxtest/linuxshellscrill/first$ read -d ":" var

dfdufdif

fdfidjf

gfgig

:

考虑CSV的数据情况

<code>function</code> <code>changeIFS(){</code>

<code>oldIFS=$IFS </code><code>#IFS的默认值是空白字符(换行符,制表符或者空格)</code>

<code>IFS=,</code>

<code>for</code> <code>item </code><code>in</code> <code>$data;</code>

<code>echo</code> <code>item: $item</code>

<code>IFS=$oldIFS</code>

<code>data=</code><code>"name,sex,rollno,location"</code> <code>#使用IFS读取变量的每一个条目</code>

<code>    </code><code>changeIFS;</code>

#IFS默认空格,这里把他变成","

输出结果

item: name

item: sex

item: rollno

item: location

<code>#!/bash/bin</code>

<code>#user of shell</code>

<code>function</code> <code>usesh(){</code>

<code>oldIFS=$IFS;</code>

<code>IFS=</code><code>":"</code><code>;</code>

<code>for</code> <code>item </code><code>in</code> <code>$line;</code>

<code>[ $count -</code><code>eq</code> <code>0 ] &amp;&amp; user=$item;</code>

<code>[ $count -</code><code>eq</code> <code>6 ] &amp;&amp; shell=$item;</code>

<code>let</code> <code>count++;</code>

<code>line=</code><code>"root:x:0:0:root:root:/bin/bash"</code>

<code>usesh;</code>

<code>echo</code> <code>$user\'s shell is $shell</code>

for循环

for var in list

do

conmend

done

echo {1..30};echo {a..z};echo {A..Z};echo {a..h};

for i in {a..z};

commend

for((i=0;i&lt;10;i++))

{

}

比较与测试

逻辑运算将它变得简洁

[ condition ] &amp;&amp; action; 如果是真执行action

[ condition ] || action; 如果是假真执行action

算术比较(数字比较)

[ $var -eq 0 ] or [ $var -ne 0 ]

其他的操作符

-gt 大于

-lt 小于

-ge 大于或等于

le 小于或等于

-eq 等于

文件相关的测试

[ -f $file_var ] 是否是文件

-x 可执行

-d 目录

-e存在

-c 字符设备路径

-b 块设备

-w 文件可写

-r 文件是否可读

-L 符号连接

判断输入的是否为文件或文件夹

<code>functionfileordir(){</code>

<code>if</code><code>[ -e $fpath ];</code><code>then</code><code># exist</code>

<code>if</code><code>[ -d $fpath ] ;</code><code>then</code><code>#directory</code>

<code>echo</code><code>$fpath is a </code><code>dir</code><code>;</code>

<code>exit</code>

<code>if</code><code>[ -f $fpath ] ;</code><code>then</code>

<code>echo</code><code>$fpath is a </code><code>file</code><code>;</code>

<code>elseecho-e </code><code>"$fpath not exit"</code><code>;</code><code>exit</code><code>;</code>

<code>echo</code><code>"unknow file type"</code>

<code>fpath=$1</code>

<code>fileordir;</code>

zhangjianlin@zhangjianlin:~/mytest/linuxtest/linuxshellscrill/first$ bash filetest.sh .

字符串比较

使用字符串比较时,最好用双括号,因为有时候采用单引号会产生错误,所以最好避开他们。

[[ $str1 == $str2 ]]

[[ $str1 != $str2 ]]

[[ $str1 &gt; $str2 ]]

[[ $str1 &lt; $str2 ]]

[[ $str1 -z $str2 ]] 空字窜

[[ $str1 -n $str2 ]] 非空字窜

if [[ $str1 &lt; $str2 ]] &amp;&amp; [[ $str1 == $str2 ]]

test命令执行条件检测

test有助于避免使用过多的括号

之前的[]测试条件同样可以用于test命令

if [ $var -eq 0 ];then echo "True";fi

if test $var -eq 0 ;then echo "True";fi

本文转自lilin9105 51CTO博客,原文链接:http://blog.51cto.com/7071976/1251283,如需转载请自行联系原作者

继续阅读