高级Bash脚本编程指南(4):shell中的引用
来源:互联网 发布:matlab for mac下载 编辑:程序博客网 时间:2024/05/22 16:32
成于坚持,败于止步
引用的字面意思就是将字符串用双引号括起来. 它的作用就是保护字符串中的特殊字符不被shell或者shell脚本重新解释, 或者扩展. (我们这里所说的"特殊"指的是一些字符在shell中具有的特殊意义, 而不是字符的字面意思, 比如通配符 -- *.)
在日常的演讲和写作中, 当我们"引用"一个短语的时候, 这意味着这个短语被区分以示它有特别的含义. 但是在Bash脚本中, 当我们引用一个字符串的时候, 我们区分这个字符串是为了保护它的字面含义.
某些程序和工具能够重新解释或者扩展被引用的特殊字符. 引用的一个重要作用就是保护命令行参数不被shell解释, 但是还是能够让正在调用的程序来扩展它.
root@ubuntu:~/resource/study/shell_study/txt-folder# grep [Tt]his *.txtfile1.txt:this is the first filefile2.txt:This the second fileroot@ubuntu:~/resource/study/shell_study/txt-folder# grep '[Tt]his' *.txtfile1.txt:this is the first filefile2.txt:This the second file
这在我的bash下都是可以实现的
引用还可以改掉echo's不换行的"毛病".
root@ubuntu:~/resource/study/shell_study/txt-folder# echo $(ls -l)total 8 -rw-r--r-- 1 root root 23 2013-04-23 23:34 file1.txt -rw-r--r-- 1 root root 21 2013-04-23 23:34 file2.txtroot@ubuntu:~/resource/study/shell_study/txt-folder# echo '$(ls -l)'$(ls -l)root@ubuntu:~/resource/study/shell_study/txt-folder# echo "$(ls -l)"total 8-rw-r--r-- 1 root root 23 2013-04-23 23:34 file1.txt-rw-r--r-- 1 root root 21 2013-04-23 23:34 file2.txt
在一个双引号中通过直接使用变量名的方法来引用变量, 一般情况下都是没问题的. 这么做将阻止所有在引号中的特殊字符被重新解释 -- 包括变量名, 但是$,`(后置引用), 和\(转义符)除外. 保留$作为特殊字符的意义是为了能够在双引号中也能够正常的引用变量("$variable"), 也就是说, 这个变量将被它的值所取代
使用双引号还能够阻止单词分割(word splitting). 如果一个参数被双引号扩起来的话, 那么这个参数将认为是一个单元, 即使这个参数包含有空白, 那里面的单词也不会被分隔开.
#!/bin/bashvar="'(]\\{}\$\""echo $var # '(]\{}$"echo "$var" # '(]\{}$" 和上一句没什么区别.Doesn't make a difference.echoIFS='\'echo $var # '(] {}$" \ 字符被空白符替换了, 为什么?echo "$var" # '(]\{}$"exit 0
我们看看上面这个脚本的执行结果:
root@ubuntu:~/resource/study/shell_study# ./echo-strange '(]\{}$"'(]\{}$"'(] {}$"'(]\{}$"针对IFS的用法以后再研究吧
当在命令行中使用时, 如果在双引号中包含"!"的话, 那么会产生一个错误(译者注: 比如, echo "hello!"). 这是因为感叹号被解释成历史命令了. 但是如果在脚本中, 就不会存在这个问题, 因为在脚本中Bash历史机制是被禁用的.
在双引号中使用"\"也可能会出现一些不一致的行为root@ubuntu:~/resource/study/shell_study# echo "hello!"bash: !": event not foundroot@ubuntu:~/resource/study/shell_study# echo hello!hello!root@ubuntu:~/resource/study/shell_study# echo hello\!hello!root@ubuntu:~/resource/study/shell_study# echo "hello\!"hello\!root@ubuntu:~/resource/study/shell_study# echo ni\thaonithaoroot@ubuntu:~/resource/study/shell_study# echo "ni\thao"ni\thaoroot@ubuntu:~/resource/study/shell_study# echo -e ni\thaonithaoroot@ubuntu:~/resource/study/shell_study# echo -e "ni\thao"nihao单引号(' ')操作与双引号基本一样, 但是不允许引用变量, 因为$的特殊意义被关闭了. 在单引号中, 任何特殊字符都按照字面的意思进行解释, 除了'. 所以说单引号("全引用")是一种比双引号("部分引用")更严格的引用方法.
因为即使是转义符(\)在单引号中也是按照字面意思解释的, 所以如果想在一对单引号中显示一个单引号是不行的
下面这个例子:
root@ubuntu:~/resource/study/shell_study# echo "I'm a good person"I'm a good personroot@ubuntu:~/resource/study/shell_study# echo 'I'm a good person'> ^Croot@ubuntu:~/resource/study/shell_study# echo 'I'\''m a good person'I'm a good personroot@ubuntu:~/resource/study/shell_study# echo 'I'"'"'m a good person'I'm a good person
转义是一种引用单个字符的方法. 一个前面放上转义符 (\)的字符就是告诉shell这个字符按照字面的意思进行解释, 换句话说, 就是这个字符失去了它的特殊含义.
在某些特定的命令和工具中, 比如echo和sed, 转义符往往会起到相反效果 - 它反倒可能会引发出这个字符的特殊含义.
特定的转义符的特殊的含义
echo和sed命令中使用
\n表示新的一
\r表示回车
\t
表示水平制表符
\v
表示垂直制表符
\b
表示后退符
\a
表示"alert"(蜂鸣或者闪烁)
\0xx
转换为八进制的ASCII码, 等价于0xx#!/bin/bashecho "\v\v\v\v" # 逐字的打印\v\v\v\v.# 使用-e选项的'echo'命令来打印转义符.echo "==============="echo -e "\v\v\v\v" # 打印4个垂直制表符.echo "==============="echo -e "\042" # 打印" (引号, 8进制的ASCII 码就是42).echo "==============="# 如果使用$'\X'结构,那-e选项就不必要了.echo $'\n' # 新行.echo $'\a' # 警告(蜂鸣).echo "==============="# 版本2以后Bash允许使用$'\nnn'结构.# 注意在这里, '\nnn\'是8进制的值.echo $'\t \042 \t' # 被水平制表符括起来的引号(").# 当然,也可以使用16进制的值,使用$'\xhhh' 结构.echo $'\t \x22 \t' # 被水平制表符括起来的引号(").echo "==============="# 分配ASCII字符到变量中.quote=$'\042' # " 被赋值到变量中.echo "$quote This is a quoted string, $quote and this lies outside the quotes."# 变量中的连续的ASCII字符.triple_underline=$'\137\137\137' # 137是八进制的'_'.echo "$triple_underline UNDERLINE $triple_underline"ABC=$'\101\102\103\010' # 101, 102, 103是八进制码的A, B, C.echo $ABCescape=$'\033' # 033 是八进制码的esc.echo "\"escape\" echoes as $escape"exit 0
结果:
root@ubuntu:~/resource/study/shell_study# ./escaped \v\v\v\v=============================="============================== " " ===============" This is a quoted string, " and this lies outside the quotes.___ UNDERLINE ___ABC"escape" echoes as
\"表示引号字面的意思
echo "Hello" # Hello
echo "\"Hello\", he said." # "Hello", he said.
\$
表示$本身子面的含义(跟在\$后边的变量名将不能引用变量的值)
echo "\$variable01" # 结果是$variable01
\\
表示反斜线字面的意思
echo "\\" # 结果是\
\的行为依赖于它自身是否被转义, 被引用(""), 或者是否出现在命令替换或here document中.
echo \z # zecho \\z # \zecho '\z' # \zecho '\\z' # \\zecho "\z" # \zecho "\\z" # \z # 命令替换echo `echo \z` # zecho `echo \\z` # zecho `echo \\\z` # \zecho `echo \\\\z` # \zecho `echo \\\\\\z` # \zecho `echo \\\\\\\z` # \\zecho `echo "\z"` # \zecho `echo "\\z"` # \z # Here documentcat <<EOF \z EOF # \zcat <<EOF \\z EOF # \z# 这些例子是由Stephane Chazelas所提供的.赋值给变量的字符串的元素也会被转义, 但是不能把一个单独的转义符赋值给变量.
variable=\echo "$variable"# 不能正常运行 - 会报错:# test.sh: : command not found# 一个"裸体的"转义符是不能够安全的赋值给变量的.## 事实上在这里"\"转义了一个换行符(变成了续航符的含义), #+ 效果就是variable=echo "$variable"#+ 不可用的变量赋值variable=\23skidooecho "$variable" # 23skidoo # 这句是可以的, 因为 #+ 第2行是一个可用的变量赋值.variable=\ # \^ 转义一个空格echo "$variable" # 显示空格variable=\\echo "$variable" # \variable=\\\echo "$variable"# 不能正常运行 - 报错:# test.sh: \: command not found## 第一个转义符把第2个\转义了,但是第3个又变成"裸体的"了,#+ 与上边的例子的原因相同.variable=\\\\echo "$variable" # \\ # 第2和第4个反斜线被转义了. # 这是正确的.转义一个空格会阻止命令行参数列表的"单词分割"问题.
file_list="/bin/cat /bin/gzip /bin/more /usr/bin/less /usr/bin/emacs-20.7"# 列出的文件都作为命令的参数.# 加两个文件到参数列表中, 列出所有的文件信息.ls -l /usr/X11R6/bin/xsetroot /sbin/dump $file_listecho "-------------------------------------------------------------------------"# 如果我们将上边的两个空个转义了会产生什么效果?ls -l /usr/X11R6/bin/xsetroot\ /sbin/dump\ $file_list# 错误: 因为前3个路径被合并成一个参数传递给了'ls -l'# 而且两个经过转义的空格组织了参数(单词)分割.转义符也提供续行功能, 也就是编写多行命令的功能. 一般的, 每一个单独行都包含一个不同的命令, 但是每行结尾的转义符都会转义换行符, 这样下一行会与上一行一起形成一个命令序列.
(cd /source/directory && tar cf - . ) | \(cd /dest/directory && tar xpvf -)# 重复Alan Cox的目录数拷贝命令,# 但是分成两行是为了增加可读性.# 也可以使用如下方式:tar cf - -C /source/directory . |tar xpvf - -C /dest/directory# 察看下边的注意事项.# (感谢, Stephane Chazelas.)如果一个脚本以|结束, 管道符, 那么就不用非的加上转义符\了. 但是一个好的编程风格, 还是应该在行尾加上转义符.
echo "foobar" #foo#barecho 'foobar' # 没什么区别.#foo#barechoecho foo\bar # 换行符被转义.#foobarechoecho "foo\bar" # 与上边一样, \在部分引用中还是被解释为续行符. #foobarechoecho 'foo\bar' # 由于是全引用, 所以\没有被解释成续行符. #foo\#bar# 由Stephane Chazelas所建议的用例.
先到这里了,O(∩_∩)O~
我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html
待续。。。。
- 高级Bash脚本编程指南(4):shell中的引用
- 高级Bash脚本编程指南(2):Shell特殊字符
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级Bash脚本编程指南
- 高级bash脚本编程指南
- 高级Bash脚本编程指南——一本深入学习shell脚本艺术的书籍
- 高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍
- 高级Bash脚本编程指南: 一本深入学习shell脚本艺术的书籍
- 高级Bash脚本编程指南学习笔记
- 高级Bash脚本编程指南--网页版
- 高级Bash脚本编程指南(15):循环
- 高级Bash脚本编程指南(1): 为什么使用shell编程
- 《高级Bash脚本编程指南》学习笔记(5)——基础:引用变量
- 如何同时启动多个Tomcat服务器
- android Message的简单实例
- 问题七十四:支配值数目。
- NSIS脚本定制安装程序包
- iOS 证书、密钥及信任服务
- 高级Bash脚本编程指南(4):shell中的引用
- Matlab、ISE联合开发实例之中值滤波(一)Matlab实现
- java编程之比较大小并计算差值(从命令窗输入数据)
- SIFT 特征提取算法总结
- Cocos2dx+lua基础ccb
- 使System.out.println("程序执行完毕!");这句话的内容输入到文件中
- 用户权限检查
- C++参考链接地址
- git创建和删除远程分支