shell中的特殊符号总结
在shell中常⽤的特殊符号罗列如下:
# ;  ;; . , / \\ 'string'| !  $  ${}  $? $$  $*
\"string\"* **  ? : ^ $#  $@ `command`{}  [] [[]] ()  (())
||  && {xx,yy,zz,...}~  ~+  ~-  &  \\<...\\>  + - %=  ==  !=
# 井号 (comments)
这⼏乎是个满场都有的符号,除了先前已经提过的\"第⼀⾏\"
#!/bin/bash
井号也常出现在⼀⾏的开头,或者位于完整指令之后,这类情况表⽰符号后⾯的是注解⽂字,不会被执⾏。
重定向过多是什么意思
# This line is comments.
echo \"a = $a\" # a = 0
由于这个特性,当临时不想执⾏某⾏指令时,只需在该⾏开头加上 # 就⾏了。这常⽤在撰写过程中。
#echo \"a = $a\" # a = 0
如果被⽤在指令中,或者引号双引号括住的话,或者在倒斜线的后⾯,那他就变成⼀般符号,不具上述的特殊功能。
~ 帐户的 home ⽬录
算是个常见的符号,代表使⽤者的 home ⽬录:cd ~;也可以直接在符号后加上某帐户的名称:cd ~user或者当成是路径的⼀部份:~/bin ~+ 当前的⼯作⽬录,这个符号代表当前的⼯作⽬录,她和内建指令 pwd的作⽤是相同的。
# echo ~+/var/log
~- 上次的⼯作⽬录,这个符号代表上次的⼯作⽬录。
# echo ~-/etc/httpd/logs
; 分号 (Command separator)
在 shell 中,担任\"连续指令\"功能的符号就是\"分号\"。譬如以下的例⼦:cd ~/backup ; mkdir startup ;cp ~/.* startup/.
;; 连续分号 (Terminator)
专⽤在 case 的选项,担任 Terminator 的⾓⾊。
case \"$fop\" inhelp) echo \"Usage: Command -help -version filename\";;version) echo \"version 0.1\" ;;esac
. 逗号 (dot,就是“点”)
在 shell 中,使⽤者应该都清楚,⼀个 dot 代表当前⽬录,两个 dot 代表上层⽬录。
CDPATH=.:~:/home:/home/web:/var:/usr/local
在上⾏ CDPATH 的设定中,等号后的 dot 代表的就是当前⽬录的意思。
如果档案名称以 dot 开头,该档案就属特殊档案,⽤ ls 指令必须加上 -a 选项才会显⽰。除此之外,在 regularexpression 中,⼀个 dot 代表匹配⼀个字元。
'string' 单引号 (single quote)
被单引号⽤括住的内容,将被视为单⼀字串。在引号内的代表变数的$符号,没有作⽤,也就是说,他被视为⼀般符号处理,防⽌任何变量替换。
heyyou=homeecho '$heyyou' # We get $heyyou
\"string\" 双引号 (double quote)
被双引号⽤括住的内容,将被视为单⼀字串。它防⽌通配符扩展,但允许变量扩展。这点与单引数的处理⽅式不同。
heyyou=homeecho \"$heyyou\" # We get home
`command` 倒引号 (backticks)
在前⾯的单双引号,括住的是字串,但如果该字串是⼀列命令列,会怎样?答案是不会执⾏。要处理这种情况,我们得⽤倒单引号来做。fdv=`date +%F`echo \"Today $fdv\"
在倒引号内的 date +%F 会被视为指令,执⾏的结果会带⼊ fdv 变数中。
,
逗点 (comma,标点中的逗号)
这个符号常运⽤在运算当中当做\"区隔\"⽤途。如下例
#!/bin/bashlet \"t1 = ((a = 5 + 3, b = 7 - 1, c = 15 / 3))\"echo \"t1= $t1, a = $a, b = $b\"
/ 斜线 (forward slash)
在路径表⽰时,代表⽬录。
cd /etc/rc.dcd ../..cd /
通常单⼀的 / 代表 root 根⽬录的意思;在四则运算中,代表除法的符号。
let \"num1 = ((a = 10 / 2, b = 25 / 5))\"
\\ 倒斜线
在交互模式下的escape 字元,有⼏个作⽤;放在指令前,有取消 aliases的作⽤;放在特殊符号前,则该特殊符号的作⽤消失;放在指令的最末端,表⽰指令连接下⼀⾏。
# type rmrm is aliased to `rm -i'# \\rm ./*.log
上例,我在 rm 指令前加上 escape 字元,作⽤是暂时取消别名的功能,将 rm 指令还原。
# bkdir=/home# echo \"Backup dir, \\$bkdir = $bkdir\"Backup dir,$bkdir = /home
上例 echo 内的 \\$bkdir,escape 将 $ 变数的功能取消了,因此,会输出 $bkdir,⽽第⼆个 $bkdir则会输出变数的内容 /home。
| 管道 (pipeline)
pipeline 是 UNIX 系统,基础且重要的观念。连结上个指令的标准输出,做为下个指令的标准输⼊。
who | wc -l
善⽤这个观念,对精简 script 有相当的帮助。
! 惊叹号(negate or reverse)
通常它代表反逻辑的作⽤,譬如条件侦测中,⽤ != 来代表\"不等于\"
if [ \"$?\" != 0 ]thenecho \"Executes error\"exit 1fi
在规则表达式中她担任 \"反逻辑\" 的⾓⾊
ls a[!0-9]
上例,代表显⽰除了a0, a1 .... a9 这⼏个⽂件的其他⽂件。
: 冒号
在 bash 中,这是⼀个内建指令:\"什么事都不⼲\",但返回状态值 0。
:
echo $? # 回应为 0
: > f.$$
上⾯这⼀⾏,相当于 cat /dev/null >f.$$。不仅写法简短了,⽽且执⾏效率也好上许多。
有时,也会出现以下这类的⽤法
: ${HOSTNAME?} ${USER?} ${MAIL?}
这⾏的作⽤是,检查这些环境变数是否已设置,没有设置的将会以标准错误显⽰错误讯息。像这种检查如果使⽤类似 test 或 if这类的做法,基本上也可以处理,但都⽐不上上例的简洁与效率。
? 问号 (wild card)
在⽂件名扩展(Filename expansion)上扮演的⾓⾊是匹配⼀个任意的字元,但不包含 null 字元。
# ls a?a1
善⽤她的特点,可以做⽐较精确的档名匹配。
* 星号 (wild card)
相当常⽤的符号。在⽂件名扩展(Filename expansion)上,她⽤来代表任何字元,包含 null 字元。
# ls a*a a1 access_log
在运算时,它则代表 \"乘法\"。
let \"fmult=2*3\"
除了内建指令 let,还有⼀个关于运算的指令expr,星号在这⾥也担任\"乘法\"的⾓⾊。不过在使⽤上得⼩⼼,他的前⾯必须加上escape 字元。
** 次⽅运算
两个星号在运算时代表 \"次⽅\" 的意思。
let \"sus=2**3\"echo \"sus = $sus\" # sus = 8
$ 钱号(dollar sign)
变量替换(Variable Substitution)的代表符号。
vrs=123echo \"vrs = $vrs\" # vrs = 123
另外,在 Regular Expressions ⾥被定义为 \"⾏\" 的最末端 (end-of-line)。这个常⽤在grep、sed、awk 以及 vim(vi) 当中。
${} 变量的正规表达式
bash 对 ${} 定义了不少⽤法。以下是取⾃线上说明的表列
${parameter:-word}  ${parameter:=word}  ${parameter:?word}  ${parameter:+word}  ${parameterffset}  ${parameterffset:length}  ${!prefix*}  ${#parameter}  ${parameter#word}  ${parameter##word}  ${parameter%word}  ${parameter%%word}
${parameter/pattern/string}  ${parameter//pattern/string}
$*
$* 引⽤script的执⾏引⽤变量,引⽤参数的算法与⼀般指令相同,指令本⾝为0,其后为1,然后依此类推。引⽤变量的代表⽅式如下:$0, $1, $2, $3, $4, $5, $6, $7, $8, $9, ${10}, ${11}.....
个位数的,可直接使⽤数字,但两位数以上,则必须使⽤ {} 符号来括住。
$* 则是代表所有引⽤变量的符号。使⽤时,得视情况加上双引号。
echo \"$*\"
还有⼀个与 $* 具有相同作⽤的符号,但效⽤与处理⽅式略为不同的符号。
$@
$@ 与 $* 具有相同作⽤的符号,不过她们两者有⼀个不同点。
符号 $* 将所有的引⽤变量视为⼀个整体。但符号 $@ 则仍旧保留每个引⽤变量的区段观念。
$#
这也是与引⽤变量相关的符号,她的作⽤是告诉你,引⽤变量的总数量是多少。
echo \"$#\"
$? 状态值 (status variable)
⼀般来说,UNIX(linux) 系统的进程以执⾏系统调⽤exit()来结束的。这个回传值就是status值。回传给⽗进程,⽤来检查⼦进程的执⾏状态。
⼀般指令程序倘若执⾏成功,其回传值为 0;失败为 1。
tar cvfz /home/user > /dev/nullecho\"$?\"$$
由于进程的ID是唯⼀的,所以在同⼀个时间,不可能有重复性的 PID。有时,script会需要产⽣临时⽂件,⽤来存放必要的资料。⽽此script 亦有可能在同⼀时间被使⽤者们使⽤。在这种情况下,固定⽂件名在写法上就显的不可靠。唯有产⽣动态⽂件名,才能符合需要。符号$$或许可以符合这种需求。它代表当前shell 的 PID。
echo \"$HOSTNAME, $USER, $MAIL\" > ftmp.$$
使⽤它来作为⽂件名的⼀部份,可以避免在同⼀时间,产⽣相同⽂件名的覆盖现象。
ps: 基本上,系统会回收执⾏完毕的 PID,然后再次依需要分配使⽤。所以 script 即使临时⽂件是使⽤动态档名的写法,如果script 执⾏完毕后仍不加以清除,会产⽣其他问题。
(  ) 指令组 (command group)
⽤括号将⼀串连续指令括起来,这种⽤法对 shell 来说,称为指令组。如下⾯的例⼦:(cd ~ ; vcgh=`pwd` ;echo $vcgh),指令组有⼀个特性,shell会以产⽣ subshell来执⾏这组指令。因此,在其中所定义的变数,仅作⽤于指令组本⾝。我们来看个例⼦
# cat ftmp-01#!/bin/basha=fsh(a=incg ; echo -e \"\\n $a \\n\")echo $a#./ftmp-01incgfsh
除了上述的指令组,括号也⽤在 array 变数的定义上;另外也应⽤在其他可能需要加上escape字元才能使⽤的场合,如运算式。(( ))
这组符号的作⽤与 let 指令相似,⽤在算数运算上,是 bash 的内建功能。所以,在执⾏效率上会⽐使⽤ let指令要好许多。
#!/bin/bash(( a = 10 ))echo -e \"inital value, a = $a\\n\"(( a++))echo \"after a++, a = $a\"
{ } ⼤括号 (Block of code)
有时候 script 当中会出现,⼤括号中会夹着⼀段或⼏段以\"分号\"做结尾的指令或变数设定。
# cat ftmp-02#!/bin/basha=fsh{a=inbc ; echo -e \"\\n $a \\n\"}echo $a#./ftmp-02inbcinbc
这种⽤法与上⾯介绍的指令组⾮常相似,但有个不同点,它在当前的 shell 执⾏,不会产⽣ subshell。
⼤括号也被运⽤在 \"函数\" 的功能上。⼴义地说,单纯只使⽤⼤括号时,作⽤就像是个没有指定名称的函数⼀般。因此,这样写 script也是相当好的⼀件事。尤其对输出输⼊的重导向上,这个做法可精简 script 的复杂度。
此外,⼤括号还有另⼀种⽤法,如下
{xx,yy,zz,...}
这种⼤括号的组合,常⽤在字串的组合上,来看个例⼦
mkdir {userA,userB,userC}-{home,bin,data}
我们得到 userA-home, userA-bin, userA-data, userB-home, userB-bin,userB-data, userC-home, userC-
bin,userC-data,这⼏个⽬录。这组符号在适⽤性上相当⼴泛。能加以善⽤的话,回报是精简与效率。像下⾯的例⼦
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
如果不是因为⽀援这种⽤法,我们得写⼏⾏重复⼏次呀!
[  ] 中括号
[  ] 中括号
常出现在流程控制中,扮演括住判断式的作⽤。if [ \"$?\" != 0 ]thenecho \"Executes error\"exit1fi
这个符号在正则表达式中担任类似 \"范围\" 或 \"集合\" 的⾓⾊
rm -r 200[1234]
上例,代表删除 2001, 2002, 2003, 2004 等⽬录的意思。
[[ ]]
这组符号与先前的 [] 符号,基本上作⽤相同,但她允许在其中直接使⽤ || 与&& 逻辑等符号。
#!/bin/bashread akif [[ $ak > 5 || $ak< 9 ]]thenecho $akfi
|| 逻辑符号
这个会时常看到,代表 or 逻辑的符号。
&& 逻辑符号
这个也会常看到,代表 and 逻辑的符号。
& 后台⼯作
单⼀个& 符号,且放在完整指令列的最后端,即表⽰将该指令列放⼊后台中⼯作。
tar cvfz data > /dev/null&
\\<...\\> 单字边界
这组符号在规则表达式中,被定义为\"边界\"的意思。譬如,当我们想寻 the 这个单字时,如果我们⽤
grep the FileA
你将会发现,像 there 这类的单字,也会被当成是匹配的单字。因为 the 正巧是 there的⼀部份。如果我们要必免这种情况,就得加上 \"边界\" 的符号
grep '\\' FileA
+ 加号 (plus)
在运算式中,她⽤来表⽰ \"加法\"。
expr 1 + 2 + 3
此外在规则表达式中,⽤来表⽰\"很多个\"的前⾯字元的意思。
# grep '10\\+9' fileB109100910000910000931010009#这个符号在使⽤时,前⾯必须加上escape 字元。
- 减号 (dash)
在运算式中,她⽤来表⽰ \"减法\"。
expr 10 - 2
此外也是系统指令的选项符号。
ls -expr 10 - 2
在 GNU 指令中,如果单独使⽤ - 符号,不加任何该加的⽂件名称时,代表\"标准输⼊\"的意思。这是 GNU指令的共通选项。譬如下例tar xpvf -
这⾥的 - 符号,既代表从标准输⼊读取资料。
不过,在 cd 指令中则⽐较特别
cd -
这代表变更⼯作⽬录到\"上⼀次\"⼯作⽬录。
% 除法 (Modulo)
在运算式中,⽤来表⽰ \"除法\"。
expr 10 % 2
此外,也被运⽤在关于变量的规则表达式当中的下列
${parameter%word}${parameter%%word}
⼀个 % 表⽰最短的 word 匹配,两个表⽰最长的 word 匹配。
= 等号 (Equals)
常在设定变数时看到的符号。
vara=123echo \" vara = $vara\"
或者像是 PATH 的设定,甚⾄应⽤在运算或判断式等此类⽤途上。
== 等号 (Equals)
常在条件判断式中看到,代表 \"等于\" 的意思。
if [ $vara == $varb ]
if [ $vara == $varb ]
...下略
!
= 不等于
常在条件判断式中看到,代表 \"不等于\" 的意思。
if [ $vara != $varb ]
...下略
^
这个符号在规则表达式中,代表⾏的 \"开头\" 位置,在[]中也与\"!\"(叹号)⼀样表⽰“⾮”
输出/输⼊重导向
> >>  <  <<  :>  &>  2&>  2<>>&  >&2
⽂件描述符(File Descriptor),⽤⼀个数字(通常为0-9)来表⽰⼀个⽂件。
常⽤的⽂件描述符如下:
⽂件描述符名称常⽤缩写默认值
0        标准输⼊ stdin    键盘
1        标准输出 stdout    屏幕
2    标准错误输出  stderr    屏幕
我们在简单地⽤<;或>时,相当于使⽤ 0< 或 1>(下⾯会详细介绍)。
* cmd > file
把cmd命令的输出重定向到⽂件file中。如果file已经存在,则清空原有⽂件,使⽤bash的noclobber选项可以防⽌复盖原有⽂件。
* cmd >> file
把cmd命令的输出重定向到⽂件file中,如果file已经存在,则把信息加在原有⽂件後⾯。
* cmd < file
使cmd命令从file读⼊
* cmd << text
从命令⾏读取输⼊,直到⼀个与text相同的⾏结束。除⾮使⽤引号把输⼊括起来,此模式将对输⼊内容进⾏shell变量替换。如果使⽤<<- ,则会忽略接下来输⼊⾏⾸的tab,结束⾏也可以是⼀堆tab再加上⼀个与text相同的内容,可以参考後⾯的例⼦。
* cmd <<< word
把word(⽽不是⽂件word)和後⾯的换⾏作为输⼊提供给cmd。
* cmd <> file
以读写模式把⽂件file重定向到输⼊,⽂件file不会被破坏。仅当应⽤程序利⽤了这⼀特性时,它才是有意义的。
* cmd >| file
功能同>,但即便在设置了noclobber时也会复盖file⽂件,注意⽤的是|⽽⾮⼀些书中说的!,⽬前仅在csh中仍沿⽤>!实现这⼀功能。
: > filename    把⽂件\"filename\"截断为0长度.# 如果⽂件不存在, 那么就创建⼀个0长度的⽂件(与'touch'的效果相同).
cmd >&n 把输出送到⽂件描述符n
cmd m>&n 把输出到⽂件符m的信息重定向到⽂件描述符n
cmd >&- 关闭标准输出
cmd <&n 输⼊来⾃⽂件描述符n
cmd m<&n m来⾃⽂件描述各个n
cmd <&- 关闭标准输⼊
cmd <&n- 移动输⼊⽂件描述符n⽽⾮复制它。(需要解释)
cmd >&n- 移动输出⽂件描述符 n⽽⾮复制它。(需要解释)
注意: >&实际上复制了⽂件描述符,这使得cmd > file 2>&1与cmd 2>&1 >file的效果不⼀样。
1、{} ⼤括号:
⽤法⼀:通配符扩展
代码:
ls my_{finger,toe}s
这条命令相当于如下命令的组合:
代码:
ls my_fingers my_toes
mkdir {userA,userB,userC}-{home,bin,data}