昊哥的NP1500私房菜

2012-02-26

第四讲 - 特殊字符及其使用



本章讲 在脚本或其他别的地方出现的特殊字符以及它们的使用方法.

******************************

第一个:#.
#在脚本中是注释的意思.
以一个#开头的行是注释行.

比如:
# 这是一行注释.

注释也可以出现在一个命令语句的后面.
echo "A comment will follow." # 这里可以添加注释.

注释前面也可以有空白字符(比如,空格和TAB).
        #注意这个注释行的开头是八个空格.


在同一行中,命令不会跟在一个注释的后面.因为这种情况下没有办法分辨注释的结尾,命令只能放在同一行的行首.

如果反过来的话,Bash不能区分哪里是注释结尾,命令不会执行.

问:也就是说只可以 命令+注释, 不可以 注释+命令?
是的.

问:运行时注释显示不出来啊?
注释只是写给看程序代码的程序员看的,并不会参与程序的运行,写不写注释程序运行效果都是一样的.

问:注释可以是中文或英文吧?
可以.注释只是写给看程序代码的程序员看的.任何字符都可以.


#注释还有一些例外.
echo "The # here does not begin a comment."
echo 'The # here does not begin a comment.'
echo The \# here does not begin a comment.
echo The # here begins a comment.
echo ${PATH#*:} # 前面的#是参数代换,不是注释.
echo $((2#101011)) # 基本转换,不是注释.

在某些情况下,#并不是注释开始的意思.

echo "The # here does not begin a comment."
echo 'The # here does not begin a comment.'
引号的引用,#将被解释为本身的意思#,最终echo会输出#.
在这里#不是注释的开头.

${var#Pattern}, ${var##Pattern}
删除从$var前端开始的最短或最长匹配$Pattern的字符串。
2#101011
的意思是,把101011从二进制转换为十进制
在这里#同样不是注释的开头.(有关${var#Pattern}和2#101011的知识以后再讲)

******************************

下面讲分号;
;是命令分隔符,它允许在同一行里有两个或更多的命令.

比如:
echo a; echo b; ls

******************************

."点"命令.这是一个bash的内建命令.
用它可以在运行时把一个文件的内容包含到脚本中.
点命令和C里的#include预编译命令很像.

比如,
#! /bin/sh
. /etc/profile
echo $TERM
exit

这个脚本在运行时,就相当于把profile文件的内容复制到这个文件里代替
. /etc/profile
那一行,然后继续执行.

点同样可以作为一个文件名的组成部分.
当点为前缀时,该文件变成了隐藏文件.这种隐藏文件ls是不会显示出来的.(除非加了-a)
在第一节的时候就讲过,ls -a会显示以点开头的隐藏文件.

在资源管理里不能直接重命名前面带点的,需要在终端用cp/mv等命令来重命名.

比如,
mv /mnt/mmc/upgrade.bin /mnt/mmc/.upgrade.bin
然后打开资源管理器->存储卡,你会发现upgrade.bin文件消失了
Windows不支持这种隐藏文件的方法,因此在Windows上会显示出来

问:那现在升级的话可行吗
不行的,因为文件名变了,需要改回来才行.

******************************

下面讲"双引号和'单引号.
引号中间引用的东西会被当作一个整体来处理,不会被空格/TAB等字符分割.比如:
echo "Hello; echo a"
会显示Hello; echo a, 分号不会被当作命令分隔符.

双引号和单引号的区别是,双引号内$等字符会被翻译成特殊含义,而单引号则不会.

比如:
hello="Hello World"
echo "$hello"
echo '$hello'

第一个"$hello"会输出Hello World,
而第二个'$hello'会输出$hello.
因此,双引号被称为部分引用,单引号被称为完全引用.

******************************

\[后斜杠]是转义符.它用来把有特殊含义的字符转换为它本身的意思.
比如,echo "\$",在这里就会输出$,$被转义为本身含义.
如果想输出\字符本身的话,可以用\\: echo "\\"

******************************

/[前斜杠]是文件路径的分隔符.比如,/mnt/mmc

******************************

`[反引号]:命令替换.
`command`结构使字符`引住的命令(command)执行结果能赋值给一个变量.

比如,
a="`ls`"
然后echo $a显示a变量的值,你会发现a的值就是ls的结果

注意,命令替换是反引号,不是单引号.

在PC键盘上,是输入区最左上角的键,esc的下面和TAB的上面.

`在机子中可以用手写的符号模式打出.
1500也可以切换到符号键盘,用键盘按shift+最上面那行,然后底下就出来候选字符,用下键切换到,数字键选择.第四个.

`ls` 等同于 $(ls), ``和$()有一样的作用.不同是,$()可以嵌套使用.

比如 a=$(dirname $(pwd))

******************************

:[冒号]空命令.
这个命令意思是空操作(即什么操作也不做).
冒号":" 命令是Bash自身内建的,它的退出状态码是真(即0).[注:shell中真用数字0表示].

冒号在循环中很有用,用冒号作为循环的条件可以生成一个死循环,因为冒号命令的返回值永远是真.

比如,
while :; do
echo "Hello"
done
会生成一个输出Hello的死循环.循环部分以后讲.

因为冒号没有任何作用,所以用冒号+重定向可以创建长度为0的文件.重定向相关内容在本节课后面会讲.

: > file1

file1的内容会被清空或是创建,创建大小为0的空文件.

如果用
: >> file2
file2如果存在,则什么也不会发生.否则会创建大小为0的file2空文件.

******************************

![感叹号]取反一个测试结果或退出状态.

例如, !=为不等于.
感叹号也可以用于间接变量引用.

例子:
#! /bin/sh
hello="Hello World"
tmp=hello
echo ${!tmp}
exit

将会输出Hello World.

${!tmp}代表着,假设tmp变量的内容为一个变量名,输出该变量的值.
在这个例子中,${!tmp}首先读取tmp变量的内容:hello,然后读取hello变量的内容:Hello World,最终的结果就是${!tmp} = Hello World.

******************************

*[星号]通配符.
星号字符是用于匹配文件名扩展的一个通配符.
它自动匹配给定的目录下的每一个文件。
echo *
会显示出当前目录下的所有文件

还有,
cp /bin/* /tmp/bin/
会把/bin文件夹下的所有文件复制到/tmp/bin文件夹下(如果存在/tmp/bin文件夹).

*在算术运算中代表乘号./代表除号.

******************************

?测试操作符.在一些表达式中,问号表示一个条件测试.
在双括号结构里,问号表示C风格的三元操作符.
在参数替换表达式里,问号测试一个变量是否被设置了值.
这些内容以后会讲到.

******************************

$变量替换 (引用一个变量的内容).
这个在上节课讲过,作用是输出变量的值.

其它用法:


${}参数替换.


$*, $@ 位置参数.

有一种特殊的变量,叫位置参数.
在运行一个脚本(或函数,这个以后讲)的时候,可以给脚本几个变量

比如,假设有个脚本叫a.sh,
a.sh 1 2 3
在a.sh运行过程中,$1 / $2 / $3的变量就分别为1 / 2 / 3

$*和$@则是所有位置变量,在这里就是`1 2 3'

a.sh:
#! /bin/sh
echo "\$1:$1"
echo "\$*:$*"
exit

然后,运行 a.sh 1 2 3 会输出:
$1:1
$*:1 2 3


$? 保存退出码值的变量.变量$?保存了一个命令,一个函数,或一个脚本的退出状态码的值.

比如,a.sh:
#! /bin/sh
exit 12

然后在终端:
# a.sh
# echo $?
12

a.sh的返回值为12.要注意的是,返回值的范围是0-255.超出这个范围会溢出.

******************************

下面讲重定向.

shell开始的时候,默认打开的有三个文件:标准输入/标准输出/错误输出.
标准输入/标准输出/错误输出在机子终端中默认是/dev/tty.
你可以把标准输入/标准输出/错误输出重定向到文件.

<用来重定向标准输入.
如果a.sh < /mnt/mmc/a,那么a.sh所有需要输入的地方都会从/mnt/mmc/a文件里来读取,而不会再要求从终端输入.

>用来重定向标准输出.
如果a.sh > /mnt/mmc/a,那么a.sh所有的输出(echo等)都会输出到/mnt/mmc/a文件,而不再会显示到终端.

2>用来错误输出.
如果a.sh > /mnt/mmc/a,那么a.sh所有的错误输出(比如语法错误消息)都会输出到/mnt/mmc/a文件,而不再会显示到终端.

这三个可以混合使用,比如
a.sh </1.txt >2.txt 2>3.txt

&>可以同时重定向标准输出和错误输出.

>>用来追加重定向文件.
如果只用>的话,那么每次使用输出到的文件就会被清空,然后输出到那个文件.
而>>是追加,文件不会被清空,输出会加到文件末尾.

******************************

|管道操作符.
它的作用是,把一个命令的标准输出作为另一个命令的标准输入.

比如,
ls | busybox grep a
会把ls的输出作为输入传递给busybox grep处理,然后grep进行筛选,选出其中含有a的行输出.
grep文本处理工具使用方法以后会讲.

|这个符号要在手写-符号里打出来.

******************************

&有个作用是后台运行.

比如,
sleep 10s &
会在后台执行sleep 10s的命令,在sleep的十秒内你可以继续运行别的命令.

******************************

-:命令的参数以它开始.比如,ls -a.


- 也代表着标准输入.

比如,
busybox grep a -
在运行后grep会处理标准输入,等待用户输入,从输入中筛选包含a的行输出.

# grep a -
abcd
abcd
bcd

abcd 和 bcd 那两行就是输入.
grep返回的只有abcd,bcd那行因为没有a字符,因此不会被输出.


在cd命令中,-的意思是先前的工作目录.

比如:
# cd /mnt/mmc                  #进入/mnt/mmc
# cd /mnt/UsrDisk              #进入/mnt/UsrDisk
# pwd                          #显示当前目录
/mnt/UsrDisk                   #命令输出
# cd -                         #返回以前的工作目录
# pwd                          #显示当前目录
/mnt/mmc                       #命令输出


-在算术运算中是负号或减号.+是加号.

******************************

=是赋值运算符,在变量赋值使用.比如
hello="Hello World"

******************************

~[波浪号]主目录或称为家目录.它与变量$HOME是一致的.在机子中是根目录/.

~+ 当前工作目录.它与变量$PWD是一致的.

~- 先前的工作目录.它与外部变量$OLDPWD是一致的.与cd -功能相同.

~ / ~+ / ~- 可用于cd和ls等,而-只能用于cd.

******************************

下面讲最后一个.空白.
空白用做函数的分隔符,分隔命令或变量.空白是由空格,制表(TAB),空行,或是由上述的组合造成的.比如,ls -a.
注意: 在某些情况下,比如变量赋值,空白是不被允许的,它会导致语法错误.
比如: hello = "Hello World" 是错误的, hello="Hello World" 正确.

******************************

下课! 起立----