赞
踩
echo
是一个 shell 内建命令,可以完成非常简单的任务。它将它的文本参数打印到标准输出中:
$ echo this is a test
this is a test
这个命令的作用是传递到
echo
命令的任一个参数都会在(屏幕上)显示出来。让我们试试另一个例子:
$ echo *
Desktop Documents ls-output.txt Music Pictures Public Templates Videos
“*”
字符意味着匹配文件名中的任意字符,shell 在echo
命令被执行前把“*”
展开成了当前工作目录下的文件名字。当回车键被按下时,shell 在命令被执行前在命令行上自动展开任何符合条件的字符,所以echo
命令的实际参数并不是“*”
,而是它展开后的结果。
通配符所依赖的工作机制叫做路径名展开。如果我们试一下在之前的章节中使用的技巧,我们会看到它们实际上是展开。给定一个家目录,它看起来像这样:
$ ls
Desktop ls-output.txt Pictures Templates
....
我们能够执行以下的展开:
$ echo D*
Desktop Documents
$ echo *s
Documents Pictures Templates Videos
$ echo [[:upper:]]*
Desktop Documents Music Pictures Public Templates Videos
查看家目录之外的目录:
$ echo /usr/*/share
/usr/kerberos/share /usr/local/share
隐藏文件路径名展开:
以圆点字符开头的文件名是隐藏文件。像这样的展开:
echo *
不会显示隐藏文件,但是展开模式以一个圆点开头,我们就能够在展开中包含隐藏文件,就像这样:
echo .*
然而,如果检查一下输出结果,会看到名字“.”
和“..”
也出现在结果中。由于它们是指当前工作目录和父目录,使用这种模式可 能会产生不正确的结果。我们可以通过这个命令来验证:
ls -d .* | less
为了在这种情况下正确地完成路径名展开,我们应该使用一个更精确的模式。这 个模式会正确地工作:
ls -d .[!.]?*
这种模式展开成所有以圆点开头,第二个字符不包含圆点,再包含至少一个字符,并且这个字符之后紧接着任意多个字符的文件名。这个命令将正确列出大多数的隐藏文件(但仍不能包含以多个圆点开头的文件名)。
带有 -A选项(“几乎所有”) 的ls
命令能够提供一份正确的隐藏文件清单:
ls -A
波浪线字符
(“∼”)
有特殊的含义,当它用在一个单词的开头时,它会展开成指定用户的家目录名
,如果没有指定用户名,则展开当前用户的家目录
:
$ echo ~
/home/me
如果有用户 “foo” 这个帐号,那么:
$ echo ~foo
/home/foo
shell 在展开中执行算数表达式。这允许我们把 shell 提示当作计算器来使用:
$ echo $((2 + 2))
4
算术表达式
展开使用这种格式:$((expression))
以上括号中的表达式是指
算术表达式
,它由数值
和算术操作符
组成。算术表达式
只支持整数(全部是数字,不带小数点),但是能执行很多不同的操作。这里是 一些它支持的操作符:
+ 加
- 减
* 乘
/ 除(但是记住,因为展开只是支持整数除法,所以结果是整数。)
% 取余,只是简单的意味着,“余数”
** 取幂
在算术表达式中空格并不重要,并且表达式可以嵌套。例如,5 的平方乘以 3:
$ echo $(($((5**2)) * 3))
75
一对括号可以用来把多个子表达式括起来。通过这个技术可以重写上面的例子,同时用一个展开代替两个,来得到一样的结果:
$ echo $(((5**2) * 3))
75
这是一个使用除法和取余操作符的例子。注意整数除法的结果:
$ echo $((5/2))
2
$ echo $((5%2))
1
花括号展开
可以从一个包含花括号的模式中创建多个文本字符串。这是一个例子:
$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back
花括号展开模式可能包含一个开头部分叫做
报头
,一个结尾部分叫做附言
。花括号表达式本身可能包含一个由逗号分开的字符串列表,或者一个整数区间,或者单个的字符的区间。这种模式不能嵌入空白字符。这个例子中使用了一个整数区间:
$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5
倒序排列的字母区间:
echo {Z..A}
Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
花括号展开可以嵌套:
$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b
那么这对什么有好处呢?最常见的应用是,创建一系列的文件或目录列表。例如想把文件按年月先后组织起来。首先,我们要创建一系列 以数值 “年-月”形式命名的目录。通过这种方式,可以使目录名按照年代顺序排列:
$ mkdir Pics
$ cd Pics
$ mkdir {2007..2009}-0{1..9} {2007..2009}-{10..12}
$ ls
2007-01 2007-07 2008-01 2008-07 2009-01 2009-07
2007-02 2007-08 2008-02 2008-08 2009-02 2009-08
2007-03 2007-09 2008-03 2008-09 2009-03 2009-09
2007-04 2007-10 2008-04 2008-10 2009-04 2009-10
2007-05 2007-11 2008-05 2008-11 2009-05 2009-11
2007-06 2007-12 2008-06 2008-12 2009-06 2009-12
参数展开
这个特性在 shell 脚本中比直接在命令行中更有用。它的许多功能和系统存储小块数据
、每块数据命名的能力
有关系(变量得命名和存储)。许多像这样的小块数据的称呼应该是变量
,可以方便地检查它们。例如,“USER”
的变量包含用户名。调用参数并查看USER
中的内容:
$ echo $USER
me
要查看有效的变量列表,可以试试这个:
$ printenv | less
在其它展开类型中,如果误输入一个模式,展开就不会发生。这时
echo
命令只简单地显示误键入的模式。但在参数展开
中,如果拼写错了一个变量名,展开仍然会进行,只是展开的结果是一个空字符串:
$ echo $SUER
$
命令替换允许把一个命令的输出作为一个展开模式来使用:
$ echo $(ls)
Desktop Documents ls-output.txt Music Pictures Public Templates
Videos
ls -l $(which cp)
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp
把
which cp
的执行结果作为一个参数传递给ls
命令,因此可以在不知道cp
命令完整路径名的情况下得到它的文件属性列表。不只限制于简单命令。也可以使用整个管道线(只展示部分输出):
$ file $(ls /usr/bin/* | grep zip)
/usr/bin/bunzip2: symbolic link to `bzip2'
....
在这个例子中,管道线的输出结果成为 file 命令的参数列表。 在旧版 shell程序中,有另一种语法也支持命令替换,可与刚提到的语法轮换使用。bash 也 支持这种语法。它使用
倒引号
来代替美元符号和括号
:
$ ls -l `which cp`
-rwxr-xr-x 1 root root 71516 2007-12-05 08:58 /bin/cp
以下面例子来说明如何控制展开:
$ echo this is a test
this is a test
shell 利用单词分割删除掉 echo 命令的参数列表中多余的空格。
引用的第一种类型,
双引号
。如果把文本放在双引号中,shell 使用的特殊字符,都失去它们的特殊含义,被当作普通字符来看待。
有几个例外:$
,\ (反斜杠)
,和‘(倒引号)
。这意味着单词分割、路径名展开、波浪线展开和花括号展开
都将失效,然而参数展开、算术展开和命令替换
仍然执行。
使用双引号可以处理包含空格的文件名。two words.txt
如果试图在命令行中使用这个文件,单词分割机制会导致这个文件名被看作两个独自的参数,而不是所期望的单个参数:
$ ls -l two words.txt
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory
使用双引号可以阻止单词分割得到期望的结果,甚至可以修复破损的文件名:
$ ls -l "two words.txt"
-rw-rw-r-- 1 me me 18 2008-02-20 13:03 two words.txt
$ mv "two words.txt" two_words.txt
双引号中,参数展开、算术表达式展开和命令替换仍然有效:
$ echo "$USER $((2+2)) $(cal)"
me 4 February 2008
Su Mo Tu We Th Fr Sa
....
单词分割机制是怎样来删除文本中额外空格:
$ echo this is a test
this is a test
在默认情况下,单词分割机制会在单词中寻找空格,制表符,和换行符,并把它们看作单词之间的界定符。这意味着无引用的空格,制表符和换行符都不是文本的一部分,它们只作为分隔符使用。由于它们把单词分为不同的参数,所以在上面的例子中,命令行包含一个带有四个不同参数的命令。加上双引号:
$ echo "this is a test"
this is a test
单词分割被禁止,内嵌的空格也不会被当作界定符,它们成为参数的一部分。一旦加上双引 号,命令行就包含一个带有一个参数的命令。事实上,单词分割机制把换行符看作界定符,对命令替换产生了一个虽然微妙但有趣的影响。下面的例子:
$ echo $(cal)
February 2008 Su Mo Tu We Th Fr Sa 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 29
$ echo "$(cal)"
February 2008
....
在第一个实例中,没有引用的命令替换导致命令行包含 38 个参数。在第二个例子中,命令行只有一个参数,参数中包括嵌入的空格和换行符。
如果需要禁止所有的展开,使用单引号。以下例子是无引用,双引号,和单引号的比较结果:
$ echo text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
text /home/me/ls-output.txt a b foo 4 me
$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER"
text ~/*.txt {a,b} foo 4 me
$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER'
text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER
正如我们所看到的,随着引用程度加强,越来越多的展开被禁止
只想引用单个字符可以在字符之前加上一个反斜杠,在这里叫做
转义字符
。 经常在双引号中使用转义字符,来有选择地阻止展开
$ echo "The balance for user $USER is: \$5.00"
The balance for user me is: $5.00
使用转义字符来消除文件名中一个字符的特殊含义,是很普遍的。例如,在文件名中可能使 用一些对于 shell 来说有特殊含义的字符。这些字符包括
“$”, ”¡‘, ” ”
等字符。在文件名中包含特殊字符:
$ mv bad\&filename good_filename
为了允许反斜杠字符出现,输入
“\”
来转义。注意在单引号中,反斜杠失去它的特殊含义,它被看作普通字符。 反斜杠转义字符序列反斜杠除了作为转义字符外,也可以构成一种表示法,来代表某种特殊字符,这些特殊字符叫做控制码。ASCII 编码表中前 32个字符被用来把命令转输到电报机之类的设备。一些编码是众所周知的(制表符,退格符,换行符,和回车符),而其它一些编码就不熟悉了(空值,传输结束码,和确认)。
转义序列 含义
\a 响铃(“警告” -导致计算机嘟嘟响)
\b 退格符
\n 新的一行。在类 Unix 系统中,产生换行。
\r 回车符
\t 制表符
上表列出了一些常见的反斜杠转义字符序列。这种利用反斜杠的表示法背后的思想来源于 C 编程语言,许多其它语言也采用了这种表示方法,包括shell。 echo 命令带上
‘-e’
选项,能够解释转义序列。你可以把转义序列放在$’ ’
里面。 以下例子中,我们可以使用sleep 命令创建一个简单的倒数计数器(sleep 是一个简单的程序,它会等待指定的秒数,然后退出):
sleep 10; echo -e ”Time’s up\a”
也可以这样做:
sleep 10; echo ”Time’s up” $’\a’
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。