简单而言,command line的每一个charactor分为如下两种:
*literal:也就是普通纯文字,对shell来说没有特殊功能。
*meta:对shell来说,具有特定功能的保留字。
literal没有什么好说的,凡是 abcd、123456 等这些“文字”都是literal。但是meta确常使我们困惑。事实上,前两章我们在command line中已碰到两个几乎每次都会碰到的meta:
*IFS:由<space> <tab> <enter>三者之一组成(我们常用space)。
*CR:由<enter>产生。
IFS是用来拆分command line的每一个词(word)用的,因为shell command line是按词来处理的。而CR则是用来结束command line用的,这也是为何我们敲<enter>命令就会执行的原因。除了IFS和CR外,常用的meta还有:
= : 设定变量。
$ : 做变量或运算替换(请不要与 shell prompt 搞混了)。
> : 重定向 stdout。
< : 重定向 stdin。
|: 管道命令。
& : 重定向 file descriptor ,或将命令置于后台执行。
( ): 将其内的命令置于 nested subshell 执行,或用于运算或命令替换。
{ }: 将其内的命令置于 non-named function 中执行,或用在变量替换的界定范围。
; : 在前一个命令结束时,而忽略其返回值,继续执行下一个命令。
&& : 在前一个命令结束时,若返回值为 true,继续执行下一个命令。
|| : 在前一个命令结束时,若返回值为 false,继续执行下一个命令。
!: 执行 history 列表中的命令
....
假如我们要在command line中将这些保留元字符的功能关闭的话,就要用到 quoting 处理了。
在bash中,我们常用的 quoting有如下三种方法:
*hard quote:''(单引号),凡在hard quote中的所有meta均被关闭。
*soft quote:""(双引号),在soft quote中的大部分meta都会被关闭,但某些保留(如$)。
*escape:\ (反斜线),只有紧接在escape(跳脱字符)之后的单一meta才被关闭。
$ A=B C # 空白键未被关闭,作为IFS 处理。
$ C: command not found.
$ echo $A
$ A="B C" # 空白键已被关闭,仅作空白符号处理。
$ echo $A
B C
一、echo 单引号、双引号和不加引号的区别
单引号会无视其中的所有特殊符号,双引号中有三种特殊字符不被忽略:$,\,`
,不加引号则不忽略所有特殊字符。例如,编写一个shell脚本,
- [lfs@lfs tmp]$ a='b c'
- [lfs@lfs tmp]$ echo $a
- b c
- lfs@lfs tmp]$ echo '$a'
- $a
下面的例子中,第二个命令由于没有关闭()这个meta,命令执行的时候shell首先解释(),当然出现错误了。
- [lfs@lfs tmp]$ echo '('$a')'
- (b c)
- [lfs@lfs tmp]$ echo ($a)
- -bash: syntax error near unexpected token `$a'
下面的例子中,因为单引号被双引号括起来,所以shell不会解释单引号,单引号就会被echo命令显示
- [lfs@lfs tmp]$ echo "('$a')"
- ('b c')
考虑一下为什么下面的例子和上面的输出结果不一样。
- [lfs@lfs tmp]$ echo '("$a")'
- ("$a")
这将打印: this is the 2nd
名为date,内容如下:
echo '$USER date *'
echo "$USER date *"
echo $USER date *
date
当前文件夹下有2个文件,分别为date和welcome,运行date输出结果为:
$USER date *
root date *
root date date welcome
在win下创建的XX.sh文件,在linux上执行,经常执行失败。对比能执行的文件,没有发现什么不同。
执行shell出现的错误是bad interpreter:No such file or directory
解决方法:
因为操作系统是windows,在windows下编辑的脚本,所以有可能有不可见字符。从的脚本及报告的错误看来, 很有可能是脚本文件是DOS格式的, 即每一行的行尾以\r\n来标识, 其ASCII码分别是0x0D, 0x0A.
可以有很多种办法看这个文件是DOS格式的还是UNIX格式的, 还是MAC格式的。
linux的换行\n,
然后用命令
:set ff
可以看到dos或unix的字样. 如果的确是dos格式的, 那么你可以用set ff=unix把它强制为unix格式的, 然后存盘退出. 再运行一遍.
(2) 用od -t x1 filename
如果你看到有0d 0a 这样的字符, 那么它是dos格式的, 如果只有0a而没有0d, 那么它是UNIX格式的, 同样可以用上述方法把它转为UNIX格式的.
1. unix2dos或dos2unix这两个小程序来做. 很简单. 在djgpp中这两个程序的名字叫dtou和utod, u代表unix, d代表dos
2. 也可以用sed 这样的工具来做:
sed 's/^M//' filename > tmp_filename
mv -f tmp_filename filename
来做