:引用““与转义 第六章:退出和退出状态exit

Posted Dontla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:引用““与转义 第六章:退出和退出状态exit相关的知识,希望对你有一定的参考价值。

原文:http://shouce.jb51.net/shell/

第一章:Shell编程 第二章:Sha-Bang(#!)开始

第三章:特殊字符

第四章. 变量和参数介绍

文章目录

第五章:引用(双引号""

引用意味着保护在引号中的字符串. 引用在保护被引起字符串中的特殊字符被shell或shell脚本解释或扩展. (如果一个字符能被特殊解释为不同于它字面上表示的意思,那么这个字符是“特殊”的,比如说通配符*.)

 bash$ ls -l [Vv]*	# 列出V和v开头的目录下的所有文件?
 -rw-rw-r--    1 bozo  bozo       324 Apr  2 15:05 VIEWDATA.BAT
 -rw-rw-r--    1 bozo  bozo       507 May  4 14:25 vartrace.sh
 -rw-rw-r--    1 bozo  bozo       539 Apr 14 17:11 viewdata.sh
 
 bash$ ls -l '[Vv]*'
 ls: [Vv]*: No such file or directory

在日常的演讲和写作中,我们使用双引号("")引用一个短语,使短语被分开以示特别。在Bash脚本中,当我们引用一个字符串,也会把它分隔开以表示它原来字面上的意思。

某些程序和软件包可以重新解释或扩展引号里的特殊字符。引号一个很重要的作用是保护命令行上的一个参数不被shell解释,而把此参数传递给要执行的程序来处理它。

 bash$ grep '[Ff]irst' *.txt
 file1.txt:This is the first line of file1.txt.
 file2.txt:This is the First line of file2.txt.

注意在Bash shell下如果没有用引号的命令grep [Ff]irst *.txt会怎么样。[1]

引号也能改掉echo's不换行的“习惯”。

 bash$ echo $(ls -l)
 total 8 -rw-rw-r-- 1 bozo bozo 130 Aug 21 12:57 t222.sh -rw-rw-r-- 1 bozo bozo 78 Aug 21 12:57 t71.sh

ar:果然不一样,加了""后,换行了,不加不换行

echo "$(ls -l)"	# 换行
echo $(ls -l)	#不换行

 bash$ echo "$(ls -l)"
 total 8
 -rw-rw-r--  1 bozo bozo 130 Aug 21 12:57 t222.sh
 -rw-rw-r--  1 bozo bozo  78 Aug 21 12:57 t71.sh

5.1. 引用变量(使用双引号除了变量名前缀($)、后引符(```)和转义符(\\)外,会使shell不再解释引号中其它所有的特殊字符)(双引号里用双引号也是可以的,它会从里层开始解析)(在echo语句中,只有句子分割和保存空白符的时候,才需要把参数用双引号引起来。.)

当要引用一个变量的值时,一般推荐使用双引号。使用双引号除了变量名[2]前缀($)、后引符()和转义符(\\)外,会使shell不再解释引号中其它所有的特殊字符。[3] 用双引号时$仍被当成特殊字符,允许引用一个被双引号引起的变量("$variable"), 那也是说$variable会被它的值所代替。(参考上面的例子 4-1).

用双引号还能使句子不被分割开. [4] 一个参数用双引号引起来能使它被看做一个单元,这样即使参数里面包含有空白字符也不会被shell分割开了。

variable1="a variable containing five words"
COMMAND This is $variable1    # 用下面7个参数执行COMMAND命令:
# "This" "is" "a" "variable" "containing" "five" "words"

COMMAND "This is $variable1"  # 用下面1个参数执行COMMAND命令:
# "This is a variable containing five words"


variable2=""    # 空字符串。

COMMAND $variable2 $variable2 $variable2        # 没有带参数执行COMMAND 命令
COMMAND "$variable2" "$variable2" "$variable2"  # 用三个含空字符串的参数执行COMMAND命令
COMMAND "$variable2 $variable2 $variable2"      # 用一个包含两个空白符的参数执行COMMAND命令

# Thanks, Stephane Chazelas.

#(反正结论就是,命令后参数加双引号是最靠谱的)

在echo语句中,只有句子分割和保存空白符的时候,才需要把参数用双引号引起来。.

例子 5-1. 引号引起奇怪的变量(反正结论就是,命令后参数加双引号是最靠谱的)(单引号里的转义字符(\\)不起作用)(解析是从左往右的)

#!/bin/bash
# weirdvars.sh: Echoing weird variables.

var="'(]\\\\\\$\\""
echo $var        # '(]\\$"
echo "$var"      # '(]\\$"     和上面一句没什么不同.

echo

IFS='\\'
echo $var        # '(] $"     \\字符被空白符替换了,为什么?(ar:为什么?)
echo "$var"      # '(]\\$"

# 以上例子由Stephane Chazelas提供..

exit 0

单引号(' ')和双引号类似,但它不允许解释变量引用,因此,在单引号内的字符$的特殊意思无效了。在单引号内,除了字符',每个特殊字符都只是字面的意思。单引号(全局引用)比双引号(部分引用)更严格的处理引用部分。

由于在单引号里的转义字符(\\)也只是被局限于字面上的意思,所以想在一双单引号里再加单引号是不行的。

echo "Why can't I write 's between single quotes"

echo

# The roundabout method.
echo 'Why can'\\''t I write '"'"'s between single quotes'
echo 'Why can'\\''t I write '\\''s between single quotes'
#    |-------|  |----------|   |-----------------------|
# 三个单引号引起的字符串之间有一个转义的单引号和一个由双引号引起的单引号.

# 这个例子得到 St閜hane Chazelas同意.

注:
[1] 除非当前目录下有一个文件名为first的文件。那这是引用的另外一个不同的理由了。(多谢 Harald Koenig指出这一点)

[2] 这也会使变量的值会有副作用。(看下面的)

[3] 在命令行上,把感叹号"!"放在双引号里执行命令会出错(译者注:比如说:echo “hello!”). 因为感叹号被解释成了一个历史命令. 然而在一个脚本文件里,这么写则是正确的,因为在脚本文件里Bash的历史机制被禁用了。

在双引号里在字符"\\"也会引起许多不一致的行为。

 bash$ echo hello\\!
 hello!
 
 
 bash$ echo "hello\\!"
 hello\\!
 
 
 
 
 bash$ echo -e x\\ty
 xty
 
 
 bash$ echo -e "x\\ty"
 x       y

(多谢Wayne Pollock指出这一点)

[4] 句子的分割,在这里是指分割一个字符串为许多不连续的单独的参数。

5.2. 转义\\

转义是引用单字符的方法.在单个字符前面的转义符(\\)告诉shell不必特殊解释这个字符,只把它当成字面上的意思。

但在一些命令和软件包里,比如说echo和sed,转义一个字符可能会引起一个相反的效果--因为它们可能触发那个字符的特殊意思。

一些转义字符的表示的特殊意思

和echo,sed连用时:

  • \\n

表示新行

  • \\r

表示回车

  • \\t

表示水平的制表符

  • \\v

表示垂直的制表符

  • \\b

表示后退符

  • \\a

表示“警告”(蜂鸣或是闪动)

  • \\0xx

翻译成ASCII码为八进制0xx所表示的字符

例子 5-2. 转义字符

#!/bin/bash
# escaped.sh: 转义字符

echo; echo

echo "\\v\\v\\v\\v"      # 打印出 \\v\\v\\v\\v literally.
# 用带着选项-e的'echo'会打印出转义字符串.
echo "============="
echo "VERTICAL TABS"
echo -e "\\v\\v\\v\\v"   # 打印四个垂直的制表符.
echo "=============="

echo "QUOTATION MARK"
echo -e "\\042"       # 打印出字符" (引号, 它的八进制ASCII码为42).	# "
echo "=============="

# 当使用像$'\\X'的结构时,-e选项是多余的.
echo; echo "NEWLINE AND BEEP"
echo $'\\n'           # 新行.
echo $'\\a'           # 警告 (蜂鸣).

echo "==============="
echo "QUOTATION MARKS"
# 版本2开始Bash已经允许使用$'\\nnn'结构了.
# 注意在这里,'\\nnn'表示一个八进制的值.
echo $'\\t \\042 \\t'   # Quote (") framed by tabs.	# 	 "

# 使用$'\\xhhh'结构也可以使用十六进制数来转义.
echo $'\\t \\x22 \\t'  # Quote (") framed by tabs.	# 	 "
# 多谢Greg Keraunen指出这个..
# 早期的Bash版本允许用'\\x022'.(译者注,现在不行了)
echo "==============="
echo


# 用ASCII码值把字符赋给变量.
# ----------------------------------------
quote=$'\\042'        # 引号"被赋给变量quote了.
echo "$quote This is a quoted string, $quote and this lies outside the quotes."	
# " This is a quoted string, " and this lies outside the quotes.

echo

# 用连串的ASCII码把一串字符赋给变量..
triple_underline=$'\\137\\137\\137'  # 137是字符'_'的ASCII码.
echo "$triple_underline UNDERLINE $triple_underline"	# ___ UNDERLINE ___

echo

ABC=$'\\101\\102\\103\\010'           # 101, 102, 103分别是A, B, C字符的八进制ASCII码.
echo $ABC	# ABC

echo; echo

escape=$'\\033'                    # 033是ESC的ASCII码的八进制值
echo "\\"escape\\" echoes as $escape"
#                                   不可见的输出.
# "escape" echoes as 	# ar:确实不可见。。。


echo; echo

exit 0

参考扩展结构$' '的另外一个例子xample 34-1.

  • \\"

表示引号(")的字面意思

echo "Hello"                  # Hello
echo "\\"Hello\\", he said."    # "Hello", he said.
  • \\$

表示美元符($)的字面意思(如果在\\$跟上变量名将不会引用变量的值)

echo "\\$variable01"  # 输出是$variable01
  • \\\\

表示反斜杠(\\)的字面意思

echo "\\\\"  # 输出是\\

# 然而 . . .

echo "\\"   # 在命令行,这句将会打印SP2变量值(译者注:变量SP2是输入未完成提示符),并要求你继续输入..
           # 在脚本文件里, 这句会出错.

反斜杠的作用要看它是否是自我转义,被引用,或出现在命令替换结构或是在here document里.
(下面代码看得我有点懵啊,,,)

                      #  简单的转义和引用
#!/bin/bash

echo \\z               #  z
echo \\\\z              # \\z
echo \\\\\\z		# \\z
echo '\\z'             # \\z
echo '\\\\z'            # \\\\z
echo "\\z"             # \\z
echo "\\\\z"            # \\z

                      #  命令替换
echo `echo \\z`        #  z
echo `echo \\\\z`       #  z
echo `echo \\\\\\z`      # \\z
echo `echo \\\\\\\\z`     # \\z
echo `echo \\\\\\\\\\\\z`   # \\z
echo `echo \\\\\\\\\\\\\\z`  # \\\\z
echo `echo "\\z"`      # \\z
echo `echo "\\\\z"`     # \\z

                      # Here document
cat <<EOF              
\\z                      
EOF                   # \\z

cat <<EOF              
\\\\z                     
EOF                   # \\z

# 这些例子由Stéphane Chazelas提供..

一个字符串赋给变量时里面的组成部分可能会被转义,但如果单独一个转义字符(\\)是不能赋给变量的。

variable=\\
echo "$variable"
# 不能工作 - 给出一个错误信息:
# test.sh: : command not found
# 单独一个转义字符是不能正确地赋给变量的.
#
#  那上面语句究竟发生了什么呢?实际上转义符"\\"转义了新行符,
#+ 产生的作用如同       variable=echo "$variable"
#+                      而这是无效的变量赋值

variable=\\
23skidoo
echo "$variable"        #  23skidoo
                        #  这样就能工作,因为第二行的变量赋值是有效的
                        #

variable=\\ 
#        \\^    转义后面的空格(译者注:粗心的读者一定要注意上面最后的空格)	# variable=\\[空格] 
echo "$variable"        # 空格

variable=\\\\
echo "$variable"        # \\

variable=\\\\\\
echo "$variable"
# 不能工作 - 产生一个错误:
# test.sh: \\: command not found
#
#  第一个\\转义第二个\\,结果只剩单独的第三个\\字符,
#+ 这样又会发生上面的情况.

variable=\\\\\\\\
echo "$variable"        # \\\\
                        # 第二和第四个\\字符被转义.
                        # 这样不会出错了.

转义一个空格可以防止一个字符串参数被分割成多个命令行参数。(转义空格:变成了一个标准字符)

file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"
# 文件列表作为参数传递给命令.

# 再加两个参数给命令ls,一同列出文件信息.
ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_list

echo "-------------------------------------------------------------------------"

# 如果我们转义上面的一对空格会发生什么?
ls -l /usr/X11R6/bin/xsetroot\\ /sbin/dump\\ $file_list
# 出错: 开头的三个文件名被连成一个文件名并传递给了命令'ls -l'
#        因为两个转义字符禁止了空格分割参数的作用。

转义符也提供了写一个多行命令的手段。一般地,每个单独的行有一个不同的命令,而在一行末尾的转义符转义新行符,命令序列则由下一行继续。

(cd /source/directory && tar cf - . ) | \\
(cd /dest/directory && tar xpvf -)
# 把Alan Cox目录树全部复制到另外一个目录里,
# 但分为两行可以增加可读性.	
# ar-用于stdinstdout重定向的源或目的(dash连接号、短破折号).(表示标准输入或标准输出)参考第三章:特殊字符(https://blog.csdn.net/Dontla/article/details/124989038)

# 你也可以用下面的命令达到一样的效果:
tar cf - -C /source/directory . |	# -C表示切换目录
tar xpvf - -C /dest/directory
# 看看下面的注释.
# (多谢,Stéphane Chazelas.)

如果一个脚本行用一个管道线"|“结束行尾,后面可以再跟一个不必一定要的转义符”\\"。然而,好的编程习惯最好加上一个转义符“\\”。

echo "foo
bar" 
#foo
#bar

echo

echo 'foo
bar'    # 没什么不同.
#foo
#bar

echo

echo foo\\
bar     # 新行符被转义.
#foobar

echo

echo "foo\\
bar"     # 还是一样,字符\\在弱引用中还是被解释为转义字符
#foobar

echo

echo 'foo\\
bar'     # 由于转义符"\\"在强引用符里,所以只能解释为字面上的意思
#foo\\
#bar

# 由Stéphane Chazelas提示写成的例子.

第六章:退出和退出状态(exit命令)

…there are dark corners in the Bourne shell, and people use all of them(Bourne shell 中存在暗角,人们都使用它们).
——Chet Ramey

exit命令一般用于结束一个脚本,就像C语言的exit一样。它也能返回一个值给父进程。

每一个命令都能返回一个退出状态(有时也看做返回状态).一个命令执行成功返回0,一个执行不成功的命令则返回一个非零值,此值通常可以被解释成一个对应的错误值。除了一些例外的情况,一个行为端庄的UNIX命令,程序或是软件包执行成功能返回0的作为退出码。

同样的,在脚本里的函数和脚本自身都会返回一个退出状态码。在脚本或函数里被执行的最后一个命令将决定退出状态码。在一个脚本里,exit nnn 命令将会返回shell一个nnn的退出状态码。(nnn必须是一个在0-255范围的十进制整数)。

如果一个脚本以不带参数的exit命令结束,脚本的退出状态码将会是执行exit命令前的最后一个命令的退出码。

#!/bin/bash

COMMAND_1

. . .

# 脚本将会以最后命令COMMAND_LAST的状态码退出。
COMMAND_LAST

exit

脚本结束没有exit,不带参数的exitexit $?三者是等价的。

#!/bin/bash

COMMAND_1

. . .

# 会以最后命令的退出码退出脚本.
COMMAND_LAST

exit $?
#!/bin/bash

COMMAND1

. . . 

# 会以最后命令的退出码退出脚本.
COMMAND_LAST

$?变量保存了最后一个命令执行后的退出状态。当一个函数返回时,$?保存了函数里最后一个命令的退出状态码。这就是Bash里函数返回值的处理办法。当一个脚本运行结束,$? 变量保存脚本的退出状态,而脚本的退出状态则是脚本中最后一个已执行命令的退出状态。并且依照惯例,0表示执行成功,1-255的整数范围表示错误。

例子 6-1. 退出/退出状态码

#!/bin/bash

echo hello
echo $?    # 因为上一条命令执行成功,打印0.

lskdf      # 无效命令.
echo $?    # 因为上面的无效命令执行失败,打印一个非零的值.

echo

exit 113   # 返回113状态码给shell.
           # 可以运行脚本结束后立即执行命令"echo $?" 检验.

#  依照惯例,命令'exit 0'表示执行成功,
#+ 当产生一个非零退出值时表示一个错误或是反常的条件。

$? 变量用于测试脚本中的命令执行结果非常的有用(参考例子 12-32和例子 12-17).

逻辑非操作符!反转一个命令或一个测试的结果,它也能反转退出状态.

例子 6-2. 逻辑非一个条件结果的用法

#!/bin/bash

true  # ture命令是内建的.	# 注释掉这句对后面没影响
echo "exit status of \\"true\\" = $?"     # 0
echo "exit status of \\"true\\" = $$?"     # 45709

! true
echo "exit status of \\"! true\\" = $?"   # 1
# 注意逻辑非字符"!"需要一个空格.
#    !true   会导致一个"command not found"(命令没有发现)的错误。
#
# 操作符'!'放在一个命令前面会导致调用Bash的历史机制。

true
!true
# 这次没有错误,也没有反转结果.
# 它只是重复执行上次的命令(true).

# 多谢, Stéphane Chazelas and Kristopher Newsome.

有一些退出状态码被用于保留(reserved meanings) 的含义,不应该在用户脚本使用。

以上是关于:引用““与转义 第六章:退出和退出状态exit的主要内容,如果未能解决你的问题,请参考以下文章

:变量访问 内部变量(内建变量位置参数其他特殊参数)

:变量访问 内部变量(内建变量位置参数其他特殊参数)

第六章

第六章读书笔记

:测试(if/then)文件测试操作符比较操作符(整数比较字符串比较混合比较)

:测试(if/then)文件测试操作符比较操作符(整数比较字符串比较混合比较)