文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>高级shell编程指南3

高级shell编程指南3

时间:2006-06-01  来源:lin_lin13

<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8"><title></title><meta name="GENERATOR" content="OpenOffice.org 2.0 (Linux)"><meta name="AUTHOR" content="lin lin"><meta name="CREATED" content="20060525;8284000"><meta name="CHANGEDBY" content="lin lin"><meta name="CHANGED" content="20060525;8323700"> <style> </style>

第二部分 基本

++++++++++++++++


第3章 特殊字符

================


# 注释,行首以#开头为注释(#!是个例外).


1 # This line is a comment.


注释也可以存在于本行命令的后边.


1 echo "A comment will follow." # 注释在这里

2 # ^ 注意#前边的空白


注释也可以在本行空白的后边.


1 # A tab precedes this comment.


注意:命令是不能跟在同一行上注释的后边的,没有办法,在同一行上,注释的后边想

要再使用命令,只能另起一行.

当然,在echo命令中被转义的#是不能作为注释的.

同样的,#也可以出现在特定的参数替换结构中或者是数字常量表达式中.


1 echo "The # here does not begin a comment."

2 echo 'The # here does not begin a comment.'

3 echo The \# here does not begin a comment.

4 echo The # 这里开始一个注释

5

6 echo ${PATH#*:} # 参数替换,不是一个注释

7 echo $(( 2#101011 )) # 数制转换,不是一个注释

8

9 # Thanks, S.C.


标准的引用和转义字符("'\)可以用来转义#


; 命令分隔符,可以用来在一行中来写多个命令.


1 echo hello; echo there

2

3

4 if [ -x "$filename" ]; then # 注意:"if"和"then"需要分隔

5 # 为啥?

6 echo "File $filename exists."; cp $filename $filename.bak

7 else

8 echo "File $filename not found."; touch $filename

9 fi; echo "File test complete."


有时候需要转义


;; 终止"case"选项.


1 case "$variable" in

2 abc) echo "\$variable = abc" ;;

3 xyz) echo "\$variable = xyz" ;;

4 esac


. .命令等价于source命令(见Example 11-20).这是一个bash的内建命令.


. .作为文件名的一部分.如果作为文件名的前缀的话,那么这个文件将成为隐藏文件.

将不被ls命令列出.


bash$ touch .hidden-file

bash$ ls -l

total 10

-rw-r--r-- 1 bozo 4034 Jul 18 22:04 data1.addressbook

-rw-r--r-- 1 bozo 4602 May 25 13:58 data1.addressbook.bak

-rw-r--r-- 1 bozo 877 Dec 17 2000 employment.addressbook

bash$ ls -al

total 14

drwxrwxr-x 2 bozo bozo 1024 Aug 29 20:54 ./

drwx------ 52 bozo bozo 3072 Aug 29 20:51 ../

-rw-r--r-- 1 bozo bozo 4034 Jul 18 22:04 data1.addressbook

-rw-r--r-- 1 bozo bozo 4602 May 25 13:58 data1.addressbook.bak

-rw-r--r-- 1 bozo bozo 877 Dec 17 2000 employment.addressbook

-rw-rw-r-- 1 bozo bozo 0 Aug 29 20:54 .hidden-file


.命令如果作为目录名的一部分的话,那么.表达的是当前目录.".."表示上一级目录.


bash$ pwd

/home/bozo/projects


bash$ cd .

bash$ pwd

/home/bozo/projects


bash$ cd ..

bash$ pwd

/home/bozo/


.命令经常作为一个文件移动命令的目的地.


bash$ cp /home/bozo/current_work/junk/* .


. .字符匹配,这是作为正则表达是的一部分,用来匹配任何的单个字符.


" 部分引用."STRING"阻止了一部分特殊字符,具体见第5章.


' 全引用. 'STRING' 阻止了全部特殊字符,具体见第5章.


, 逗号链接了一系列的算术操作,虽然里边所有的内容都被运行了,但只有最后一项被

返回.


如:

1 let "t2 = ((a = 9, 15 / 3))" # Set "a = 9" and "t2 = 15 / 3"


\ 转义字符,如\X等价于"X"或'X',具体见第5章.


/ 文件名路径分隔符.或用来做除法操作.


` 后置引用,命令替换,具体见第14章


: 空命令,等价于"NOP"(no op,一个什么也不干的命令).也可以被认为与shell的内建命令(true)作用相同.":"命令是一

个bash的内建命令,它的返回值为0,就是shell返回的true.


如:

1 :

2 echo $? # 0


死循环,如:


1 while :

2 do

3 operation-1

4 operation-2

5 ...

6 operation-n

7 done

8

9 # 与下边相同:

10 # while true

11 # do

12 # ...

13 # done


在if/then中的占位符,如:

1 if condition

2 then : # 什么都不做,引出分支.

3 else

4 take-some-action

5 fi


在一个2元命令中提供一个占位符,具体见Example 8-2,和"默认参数".如:

1 : ${username=`whoami`}

2 # ${username=`whoami`} 如果没有":"的话,将给出一个错误,除非"username"是

3 # 个命令

在here document中提供一个占位符,见Example 17-10.


使用"参数替换"来评估字符串变量(见Example 9-14).如:

1 : ${HOSTNAME?} ${USER?} ${MAIL?}

2 # 如果一个或多个必要的环境变量没被设置的话,

3 #+ 就打印错误信息.


"变量扩展/子串替换"

在和 > (重定向操作符)结合使用时,把一个文件截断到0长度,没有修改它的权限.

如果文件在之前并不存在,那么就创建它.如:

1 : > data.xxx #文件"data.xxx"现在被清空了.

2

3 #与 cat /dev/null >data.xxx 的作用相同

4 #然而,这不会产生一个新的进程,因为":"是一个内建命令.

具体参见Example 12-14.


在和>>重定向操作符结合使用时,将不会对想要附加的文件产生任何影响.

如果文件不存在,将创建.

注意: 这只适用于正规文件,而不是管道,符号连接,和某些特殊文件.


也可能用来作为注释行,虽然我们不推荐这么做.使用#来注释的话,将关闭剩余行的

错误检查,所以可以在注释行中写任何东西.然而,使用:的话将不会这样.如:

1 : This is a comment thar generates an error,(if [ $x -eq 3] ).


":"还用来在/etc/passwd和$PATH变量中用来做分隔符.

bash$ echo $PATH

/usr/local/bin:/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games

! 取反操作符,将反转"退出状态"结果,(见Example 6-2).也会反转test操作符的意义.比

如修改=为!=.!操作是Bash的一个关键字.


在一个不同的上下文中,!也会出现在"间接变量引用"见Example 9-22.


在另一种上下文中,!还能反转bash的"history mechanism"(见附录J 历史命令)

需要注意的是,在一个脚本中,"history mechanism"是被禁用的.


* 万能匹配字符,用于文件名匹配(这个东西有个专有名词叫file globbing),或者是正则

表达式中.注意:在正则表达式匹配中的作用和在文件名匹配中的作用是不同的.

bash$ echo *

abs-book.sgml add-drive.sh agram.sh alias.sh

* 数学乘法.

**是幂运算.

? 测试操作.在一个确定的表达式中,用?来测试结果.

(())结构可以用来做数学计算或者是写c代码,那?就是c语言的3元操作符的

一个.

在"参数替换"中,?测试一个变量是否被set了.

? 在file globbing中和在正则表达式中一样匹配任意的单个字符.


$ 变量替换

1 var1=5

2 var2=23skidoo

3

4 echo $var1 # 5

5 echo $var2 # 23skidoo

$ 在正则表达式中作为行结束符.

${} 参数替换,见9.3节.

$*,$@ 位置参数

$? 退出状态变量.$?保存一个命令/一个函数或者脚本本身的退出状态.

$$ 进程ID变量.这个$$变量保存运行脚本进程ID

() 命令组.如:

1 (a=hello;echo $a)

注意:在()中的命令列表,将作为一个子shell来运行.

在()中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的.

如:

1 a=123

2 ( a=321; )

3

4 echo "a = $a" # a = 123

5 # 在圆括号中a变量,更像是一个局部变量.


用在数组初始化,如:

1 Array=(element1,element2,element3)


{xxx,yyy,zzz...}

大括号扩展,如:

1 cat {file1,file2,file3} > combined_file

2 # 把file1,file2,file3连接在一起,并且重定向到combined_file中.

3

4

5 cp file22.{txt,backup}

6 # 拷贝"file22.txt" 到"file22.backup"中


一个命令可能会对大括号中的以逗号分割的文件列表起作用[1]. file globbing将对

大括号中的文件名作扩展.

注意: 在大括号中,不允许有空白,除非这个空白是有意义的.

echo {file1,file2}\ :{\ A," B",' C'}

file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C

{} 代码块.又被称为内部组.事实上,这个结构创建了一个匿名的函数.但是与函数不同的

是,在其中声明的变量,对于脚本其他部分的代码来说还是可见的.如:

bash$

{

local a;

a= 123;

}

bash中的local申请的变量只能够用在函数中.


1 a=123

2 { a=321; }

3 echo "a = $a" # a = 321 (说明在代码块中对变量a所作的修改,影响了外边的变量a)

4

5 # Thanks, S.C.


下边的代码展示了在{}结构中代码的I/O重定向.


Example 3-1. 代码块和I/O重定向

################################Start Script#######################################

1 #!/bin/bash

2 # 从 /etc/fstab中读行

3

4 File=/etc/fstab

5

6 {

7 read line1

8 read line2

9 } < $File

10

11 echo "First line in $File is:"

12 echo "$line1"

13 echo

14 echo "Second line in $File is:"

15 echo "$line2"

16

17 exit 0

18

19 # 现在,你怎么分析每行的分割域

20 # 暗示: 使用 awk.

################################End Script#########################################


Example 3-2. 将一个代码块的结果保存到文件

################################Start Script#######################################

1 #!/bin/bash

2 # rpm-check.sh

3

4 # 这个脚本的目的是为了描述,列表,和确定是否可以安装一个rpm包.

5 # 在一个文件中保存输出.

6 #

7 # 这个脚本使用一个代码块来展示

8

9 SUCCESS=0

10 E_NOARGS=65

11

12 if [ -z "$1" ]

13 then

14 echo "Usage: `basename $0` rpm-file"

15 exit $E_NOARGS

16 fi

17

18 {

19 echo

20 echo "Archive Description:"

21 rpm -qpi $1 # 查询说明

22 echo

23 echo "Archive Listing:"

24 rpm -qpl $1 # 查询列表

25 echo

26 rpm -i --test $1 # 查询rpm包是否可以被安装

27 if [ "$?" -eq $SUCCESS ]

28 then

29 echo "$1 can be installed."

30 else

31 echo "$1 cannot be installed."

32 fi

33 echo

34 } > "$1.test" # 把代码块中的所有输出都重定向到文件中

35

36 echo "Results of rpm test in file $1.test"

37

38 # 查看rpm的man页来查看rpm的选项

39

40 exit 0

################################End Script#########################################

注意: 与()中的命令不同的是,{}中的代码块将不能正常地开启一个新shell.[2]


{} \; 路径名.一般都在find命令中使用.这不是一个shell内建命令.

注意: ";"用来结束find命令序列的-exec选项.


[] test.

test的表达式将在[]中.

值得注意的是[是shell内建test命令的一部分,并不是/usr/bin/test中的扩展命令

的一个连接.


[[]] test.

test表达式放在[[]]中.(shell关键字)

具体查看[[]]结构的讨论.


[] 数组元素

Array[1]=slot_1

echo ${Array[1]}


[] 字符范围

在正则表达式中使用,作为字符匹配的一个范围


(()) 数学计算的扩展

在(())结构中可以使用一些数字计算.

具体参阅((...))结构.


>&>>&>><

重定向.

scriptname >filename 重定向脚本的输出到文件中.覆盖文件原有内容.

command &>filename 重定向stdout和stderr到文件中

command >&2 重定向command的stdout到stderr

scriptname >>filename 重定向脚本的输出到文件中.添加到文件尾端,如果没有文件,

则创建这个文件.


进程替换,具体见"进程替换部分",跟命令替换极其类似.

(command)>

<(command)


<和> 可用来做字符串比较

<和> 可用在数学计算比较


<< 重定向,用在"here document"


<<< 重定向,用在"here string"


<,> ASCII比较

1 veg1=carrots

2 veg2=tomatoes

3

4 if [[ "$veg1" < "$veg2" ]]

5 then

6 echo "Although $veg1 precede $veg2 in the dictionary,"

7 echo "this implies nothing about my culinary preferences."

8 else

9 echo "What kind of dictionary are you using, anyhow?"

10 fi


\<,\> 正则表达式中的单词边界.如:

bash$grep '\<the\>' textfile

| 管道.分析前边命令的输出,并将输出作为后边命令的输入.这是一种产生命令链的

好方法.

1 echo ls -l | sh

2 # 传递"echo ls -l"的输出到shell中,

3 #+ 与一个简单的"ls -l"结果相同.

4

5

6 cat *.lst | sort | uniq

7 # 合并和排序所有的".lst"文件,然后删除所有重复的行.

管道是进程间通讯的一个典型办法,将一个进程的stdout放到另一个进程的stdin中.

标准的方法是将一个一般命令的输出,比如cat或echo,传递到一个过滤命令中(在这个

过滤命令中将处理输入),得到结果,如:

cat $filename1 | $filename2 | grep $search_word


当然输出的命令也可以传递到脚本中.如:

################################Start Script#######################################

1 #!/bin/bash

2 # uppercase.sh : 修改输出,全部转换为大写

3

4 tr 'a-z' 'A-Z'

5 # 字符范围必须被""引用起来

6 #+ 来阻止产生单字符的文件名.

7

8 exit 0

################################End Script#########################################

现在让我们输送ls -l的输出到一个脚本中.

bash$ ls -l | ./uppercase.sh

-RW-RW-R-- 1 BOZO BOZO 109 APR 7 19:49 1.TXT

-RW-RW-R-- 1 BOZO BOZO 109 APR 14 16:48 2.TXT

-RW-R--R-- 1 BOZO BOZO 725 APR 20 20:56 DATA-FILE


注意:管道中的一个进程的stdout必须被下一个进程作为stdin读入.否则,数据流会阻

塞,并且管道将产生非预期的行为.

如:

1 cat file1 file2 | ls -l | sort

2 #从"cat file1 file2"中的输出并没出现


作为子进程的运行的管道,不能够改变脚本的变量.

1 variable="initial_value"

2 echo "new_value" | read variable

3 echo "variable = $variable" #variable = initial_value

如果管道中的某个命令产生了一个异常,并中途失败,那么这个管道将过早的终止.

这种行为被叫做a broken pipe,并且这种状态下将发送一个SIGPIPE信号.


>| 强制重定向(即使设置了noclobber选项--就是-C选项).这将强制的覆盖一个现存文件.


|| 或-逻辑操作.


& 后台运行命令.一个命令后边跟一个&,将表示在后台运行.

bash$sleep 10 &

[1] 850

[1]+ Done sleep 10

在一个脚本中,命令和循环都可能运行在后台.


Example 3-3. 在后台运行一个循环

################################Start Script#######################################

1 #!/bin/bash

2 #background-loop.sh

3

4 for i in 1 2 3 4 5 6 7 8 9 10 #第一个循环

5 do

6 echo -n "$i"

7 done& #在后台运行这个循环

8 #在第2个循环之后,将在某些时候执行.

9

10 echo #这个'echo'某些时候将不会显示.

11

12 for i in 11 12 13 14 15 16 17 18 19 20 #第二个循环

13 do

14 echo -n "$i"

15 done

16

17 echo #这个'echo'某些时候将不会显示.

18

19 #--------------------------------------------------------

20

21 #期望的输出应该是

22 #1 2 3 4 5 6 7 8 9 10

23 #11 12 13 14 15 16 17 18 19 20

24

25 #然而实际的结果有可能是

26 #11 12 13 14 15 16 17 18 19 20

27 #1 2 3 4 5 6 7 8 9 10 bozo $

28 #(第2个'echo'没执行,为什么?)

29

30 #也可能是

31 #1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

32 #(第1个'echo'没执行,为什么?)

33

34 #非常少见的执行结果,也有可能是:

35 #11 12 13 1 2 3 4 5 6 7 8 9 10 14 15 16 17 18 19 20

36 #前台的循环先于后台的执行

37

38 exit 0

39

40 # Nasimuddin Ansari 建议加一句 sleep 1

41 #+ 在 6行和14行的 echo -n "$i"之后加

42 #+ 将看到一些乐趣

################################End Script#########################################

注意:在一个脚本内后台运行一个命令,有可能造成这个脚本的挂起,等待一个按键

响应.幸运的是,我们可以在Example 11-24附近,看到这个问题的解决办法.


&& 与-逻辑操作.


- 选项,前缀.在所有的命令内如果想使用选项参数的话,前边都要加上"-".


COMMAND -[Option1][Option2][...]

ls -al

sort -dfu $filename

set -- $variable


1 if [ $file1 -ot $file2 ]

2 then

3 echo "File $file1 is older than $file2."

4 fi

5

6 if [ "$a" -eq "$b" ]

7 then

8 echo "$a is equal to $b."

9 fi

10

11 if [ "$c" -eq 24 -a "$d" -eq 47 ]

12 then

13 echo "$c equals 24 and $d equals 47."

14 fi


- 用于重定向 stdin 或 stdout.


################################Start Script#######################################

1 (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xpvf -)

2 # 从一个目录移动整个目录树到另一个目录

3 # [courtesy Alan Cox <[email protected]>, with a minor change]

4

5 # 1) cd /source/directory 源目录

6 # 2) && 与操作,如果cd命令成功了,那么就执行下边的命令

7 # 3) tar cf - . 'c'创建一个新文档,'f'后边跟'-'指定目标文件作为stdout

8 # '-'后边的'f'(file)选项,指明作为stdout的目标文件.

9 # 并且在当前目录('.')执行.

10 # 4) | 管道...

11 # 5) ( ... ) 一个子shell

12 # 6) cd /dest/directory 改变当前目录到目标目录.

13 # 7) && 与操作,同上.

14 # 8) tar xpvf - 'x'解档,'p'保证所有权和文件属性,

15 # 'v'发完整消息到stdout

16 # 'f'后边跟'-',从stdin读取数据

17 #

18 # 注意:'x' 是一个命令, 'p', 'v', 'f' 是选项.

19 # Whew!

20

21

22

23 # 更优雅的写法应该是

24 # cd source/directory

25 # tar cf - . | (cd ../dest/directory; tar xpvf -)

26 #

27 # 当然也可以这么写:

28 # cp -a /source/directory/* /dest/directory

29 # 或者:

30 # cp -a /source/directory/* /source/directory/.[^.]* /dest/directory

31 # 如果在/source/directory中有隐藏文件的话.

################################End Script#########################################


################################Start Script#######################################

1 bunzip2 linux-2.6.13.tar.bz2 | tar xvf -

2 # --未解压的tar文件-- | --然后把它传递到"tar"中--

3 # 如果 "tar" 没能够正常的处理"bunzip2",

4 # 这就需要使用管道来执行2个单独的步骤来完成它.

5 # 这个练习的目的是解档"bzipped"的kernel源文件.

################################End Script#########################################

注意:在上边这个例子中'-'不太象是bash的操作符,而更像是tar的参数.

bash$echo "whatever" | cat -

whatever


在需要一个文件名的地方,-重定向输出到stdout(如在tar和cf命令中),或者从

stdin中接受输入,而不是从一个文件中接受输入.这是在管道中作为一个过滤

器,来使用文件定位工具的一种办法.

bash$file

用法: file [-bciknvzl] [-f namefile] [-m magicfiles] file...

上边这个例子file将会出错,提示你如何使用file命令.


添加一个"-"将得到一个更有用的结果.这将使得shell等待用户输入.

bash$file -

abc

standard input: ASCII text


bash$file -

#!/bin/bash

standard input: Bourn-Again shell script tesxt executable


现在命令从stdin中接受了输入,并分析它.


"-"常用于管道后边的命令,具体参看33.7节,来看使用技巧.

使用diff命令来和另一个文件的一部分进行比较.

grep Linux file1 | diff file2 -


最后,一个真实世界的使用tar命令的例子.


Example 3-4. 备份最后一天所有修改的文件.

################################Start Script#######################################

1 #!/bin/bash

2

3 # 在一个"tarball"中(经过tar和gzip处理过的文件)

4 #+ 备份最后24小时当前目录下d所有修改的文件.

5

6 BACKUPFILE=backup-$(date +%m-%d-%Y)

7 # 在备份文件中嵌入时间.

8 # Thanks, Joshua Tschida, for the idea.

9 archive=${1:-$BACKUPFILE}

10 # 如果在命令行中没有指定备份文件的文件名,

11 #+ 那么将默认使用"backup-MM-DD-YYYY.tar.gz".

12

13 tar cvf - `find . -mtime -1 -type f -print` > $archive.tar

14 gzip $archive.tar

15 echo "Directory $PWD backed up in archive file \"$archive.tar.gz\"."

16

17

18 # Stephane Chazelas指出上边代码,

19 #+ 如果在发现太多的文件的时候,或者是如果文件

20 #+ 名包括空格的时候,将执行失败.

21

22 # Stephane Chazelas建议使用下边的两种代码之一

23 # -------------------------------------------------------------------

24 # find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$archive.tar"

25 # 使用gnu版本的find.

26

27

28 # find . -mtime -1 -type f -exec tar rvf "$archive.tar" '{}' \;

29 # 对于其他风格的UNIX便于移植,但是比较慢.

30 # -------------------------------------------------------------------

31

32

33 exit 0

################################End Script#########################################


注意:以"-"开头的文件名在使用"-"作为重定向操作符的时候,可能会产生问题.

应该写一个脚本来检查这个问题,并给这个文件加上合适的前缀.如:

./-FILENAME, $PWD/-FILENAME,或$PATHNAME/-FILENAME.


如果变量的值以"-"开头,可能也会引起问题.

1 var="-n"

2 echo $var

3 #具有"echo -n"的效果了,这样什么都不会输出的.


- 之前工作的目录."cd -"将回到之前的工作目录,具体请参考"$OLDPWD"环境变量.

注意:一定要和之前讨论的重定向功能分开,但是只能依赖上下文区分.


- 算术减号.


= 算术等号,有时也用来比较字符串.

1 a=28

2 echo $a # 28


+ 算术加号,也用在正则表达式中.

+ 选项,对于特定的命令来说使用"+"来打开特定的选项,用"-"来关闭特定的选项.


% 算术取模运算.也用在正则表达式中.


~ home目录.相当于$HOME变量.~bozo是bozo的home目录,并且ls ~bozo将列出其中的

内容. ~/就是当前用户的home目录,并且ls ~/将列出其中的内容,如:

bash$ echo ~bozo

/home/bozo


bash$ echo ~

/home/bozo


bash$ echo ~/

/home/bozo/


bash$ echo ~:

/home/bozo:


bash$ echo ~nonexistent-user

~nonexistent-user


~+ 当前工作目录,相当于$PWD变量.


~- 之前的工作目录,相当于$OLDPWD内部变量.


=~ 用于正则表达式,这个操作将在正则表达式匹配部分讲解,只有version3才支持.


^ 行首,正则表达式中表示行首."^"定位到行首.



控制字符

修改终端或文本显示的行为.控制字符以CONTROL + key组合.

控制字符在脚本中不能正常使用.

Ctl-B 光标后退,这应该依赖于bash输入的风格,默认是emacs风格的.

Ctl-C Break,终止前台工作.

Ctl-D 从当前shell登出(和exit很像)

"EOF"(文件结束符).这也能从stdin中终止输入.

在console或者在xterm window中输入的时候,Ctl-D将删除光标下字符.

当没有字符时,Ctrl-D将退出当前会话.在xterm window也有关闭窗口

的效果.

Ctl-G beep.在一些老的终端,将响铃.

Ctl-H backspace,删除光标前边的字符.如:

1 #!/bin/bash

2 # 在一个变量中插入Ctl-H

3

4 a="^H^H" # 两个 Ctl-H (backspaces).

5 echo "abcdef" # abcdef

6 echo -n "abcdef$a " # abcd f

7 # 注意结尾的空格 ^ ^ 两个 twice.

8 echo -n "abcdef$a" # abcdef

9 # 结尾没有空格 没有 backspace 的效果了(why?).

10 # 结果并不像期望的那样

11 echo; echo

Ctl-I 就是tab键.

Ctl-J 新行.

Ctl-K 垂直tab.(垂直tab?新颖,没听过)

作用就是删除光标到行尾的字符.

Ctl-L clear,清屏.

Ctl-M 回车

################################Start Script#######################################

1 #!/bin/bash

2 # Thank you, Lee Maschmeyer, for this example.

3

4 read -n 1 -s -p $'Control-M leaves cursor at beginning of this line. Press Enter. \x0d'

5 #当然,'0d'就是二进制的回车.

6 echo >&2 # '-s'参数使得任何输入都不将回显出来

7 #+ 所以,明确的重起一行是必要的.

8

9 read -n 1 -s -p $'Control-J leaves cursor on next line. \x0a'

10 echo >&2 # Control-J 是换行.

11

12 ###

13

14 read -n 1 -s -p $'And Control-K\x0bgoes straight down.'

15 echo >&2 # Control-K 是垂直制表符.

16

17 # 关于垂直制表符效果的一个更好的例子见下边:

18

19 var=$'\x0aThis is the bottom line\x0bThis is the top line\x0a'

20 echo "$var"

21 # 这句与上边的例子使用的是同样的办法,然而:

22 echo "$var" | col

23 # 这将造成垂直制表符右边的部分在左边部分的上边.

24 # 这也解释了为什么我们要在行首和行尾加上一个换行符--

25 #+ 来避免一个混乱的屏幕输出.

26

27 # Lee Maschmeyer的解释:

28 # ---------------------

29 # In the [first vertical tab example] . . . the vertical tab

29 # 在这里[第一个垂直制表符的例子中] . . . 这个垂直制表符

30 #+ makes the printing go straight down without a carriage return.

31 # This is true only on devices, such as the Linux console,

32 #+ that can't go "backward."

33 # The real purpose of VT is to go straight UP, not down.

34 # It can be used to print superscripts on a printer.

34 # 它可以用来在一个打印机上打印上标.

35 # col的作用,可以用来模仿VT的合适的行为.

36

37 exit 0

################################End Script#########################################

Ctl-Q 继续(等价于XON字符),这个继续的标准输入在一个终端里

Ctl-S 挂起(等价于XOFF字符),这个被挂起的stdin在一个终端里,用Ctl-Q恢复

Ctl-U 删除光标到行首的所有字符,在某些设置下,删除全行.

Ctl-V 当输入字符时,Ctl-V允许插入控制字符.比如,下边2个例子是等价的

echo -e '\x0a'

echo <Ctl-V><Ctl-J>

Ctl-V在文本编辑器中十分有用,在vim中一样.

Ctl-W 删除当前光标到前边的最近一个空格之间的字符.

在某些设置下,删除到第一个非字母或数字的字符.

Ctl-Z 终止前台工作.

空白部分

分割命令或者是变量.包括空格,tab,空行,或任何它们的组合.

在一些特殊情况下,空白是不允许的,如变量赋值时,会引起语法错误.

空白行在脚本中没有效果.

"$IFS",对于某些命令输入的特殊变量分割域,默认使用的是空白.

如果想保留空白,使用引用.


注意事项:

[1] shell做大括号的命令扩展.但是命令本身需要对扩展的结果作处理.

[2] 例外:在pipe中的一个大括号中的代码段可能运行在一个子shell中.

1 ls | { read firstline; read secondline; }

2 # 错误,在打括号中的代码段,将运行到子shell中.

3 #+ 所以ls的输出将不能传递到代码块中.

4 echo "First line is $firstline; second line is $secondline" # 不能工作

5

6 # Thanks, S.C.

[3] 换行符也被认为是空白.这也解释了为什么一个空行也会被认为是空白.




相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载