全部博文(584)
分类: LINUX
2010-01-06 15:17:16
摘自《高级bash脚本编程指南》
命 令替换能够重新分配一个(对于命令替换来说, 这个命令既可以是外部的系统命令, 也可以是内部脚本的内建命令, 甚至可以是脚本函数. ) 甚至是多个命令的输出; 它会将命令的输出如实地添加到另一个上下文中. (从技术的角度来讲, 命令替换将会抽取一个命令的输出, 然后使用=操作将其赋值到一个变量中. )
命令替换的典型用法形式, 是使用后置引用(`…`). 使用后置引用的(反引号)命令会产生命令行文本.
1 script_name=`basename $0`
2 echo "The name of this script is $script_name."
这样一来, 命令的输出就能够保存到变量中, 或者传递到另一个命令中作为这个命令的参数, 甚至可以用来产生for循环的参数列表. .
注:命令替换将会调用一个 subshell.
命令替换可能会引起单词分割(word split).
1 COMMAND `echo a b` # 两个参数: a and b
2
3 COMMAND "`echo a b`" # 1个参数: "a b"
4
5 COMMAND `echo` # 无参数
6
7 COMMAND "`echo`" # 一个空参数
8
9
10 # 感谢, S.C.
即使没有引起单词分割(word split), 命令替换也会去掉多余的新行.
如果用echo命令输出一个未引用变量, 而且这个变量以命令替换的结果作为值, 那么这个变量中的换行符将会被删除. 这可能会引起一些异常状况.
1 dir_listing=`ls -l`
2 echo $dir_listing # 未引用, 就是没用引号括起来
3
4 # 期望打印出经过排序的目录列表.
5
6 # 可惜, 我们只能获得这些:
7 # total 3 -rw-rw-r-- 1 bozo bozo 30 May 13 17:15 1.txt -rw-rw-r-- 1 bozo
8 # bozo 51 May 15 20:57 t2.sh -rwxr-xr-x 1 bozo bozo 217 Mar 5 21:13 wi.sh
9
10 # 新行消失了.
11
12
13 echo "$dir_listing" # 引用起来
14 # -rw-rw-r-- 1 bozo 30 May 13 17:15 1.txt
15 # -rw-rw-r-- 1 bozo 51 May 15 20:57 t2.sh
16 # -rwxr-xr-x 1 bozo 217 Mar 5 21:13 wi.sh
命令替换甚至允许将整个文件的内容放到变量中, 可以使用重定向或者cat命令.
1 variable1=`2 variable2=`cat file2` # 将"file2"的内容放到"variable2"中.
3 # 但是这行将会fork一个新进程,
4 #+ 所以这行代码将会比第一行代码执行得慢.
5
6 # 注意:
7 # 变量中可以包含空白,
8 #+ 甚至是(厌恶至极的), 控制字符.
注:不要将一个长文本文件的全部内容设置到变量中, 除非你有一个非常好的原因非这么做不可, 也不要将二进制文件的内容保存到变量中, 即使是开玩笑也不行.
变量替换允许将一个loop的输出设置到一个变量中. 这么做的关键就是将循环中echo命令的输出全部截取.
例子 1. 将一个循环输出的内容设置到变量中
1 #!/bin/bash
2 # csubloop.sh: 将循环输出的内容设置到变量中.
3
4 variable1=`for i in 1 2 3 4 5
5 do
6 echo -n "$i" # 对于在这里的命令替换来说
7 done` #+ 这个'echo'命令是非常关键的.
8
9 echo "variable1 = $variable1" # variable1 = 12345
10
11
12 i=0
13 variable2=`while [ "$i" -lt 10 ]
14 do
15 echo -n "$i" # 再来一个, 'echo'是必需的.
16 let "i += 1" # 递增.
17 done`
18
19 echo "variable2 = $variable2" # variable2 = 0123456789
20
21 # 这就证明了在一个变量的声明中
22 #+ 嵌入一个循环是可行的.
23
24 exit 0
命令替换使得扩展有效Bash工 具集变为可能 这样, 写一段小程序或者一段脚本就可以达到目的. 因为程序或脚本的输出会传到stdout上(就像一个标准UNIX工具所做的那样), 然后重新将这些输出保存到变量中. (译者: 作者的意思就是在这种情况下写脚本和写程序作用是一样的.)
1 #include
2
3 /* "Hello, world." C program */
4
5 int main()
6 {
7 printf( "Hello, world." );
8 return (0);
9 }
bash$ gcc -o hello hello.c
1 #!/bin/bash
2 # hello.sh
3
4 greeting=`./hello`
5 echo $greeting
bash$ sh hello.sh
Hello, world.
对于命令替换来说, $(COMMAND)形式已经取代了后置引用”`”.
1 output=$(sed -n /"$1"/p $file) # 来自于例子"grp.sh".
2
3 # 将文本文件的内容保存到一个变量中.
4 File_contents1=$(cat $file1)
5 File_contents2=$(<$file2) # Bash也允许这么做.
$(…)形式的命令替换在处理双反斜线(\\)时与`…`形式不同.
bash$ echo `echo \\`
bash$ echo $(echo \\)
\
$(…)形式的命令替换是允许嵌套的.
word_count=$( wc -w $(ls -l | awk '{print $9}') )
或者, 可以更加灵活 . . .
事实上, 对于后置引用的嵌套是可行的, 但是只能将内部的反引号转义才行.
word_count=` wc -w \`ls -l | awk '{print $9}'\` `
算术扩展
算术扩展提供了一种强力工具, 可以在脚本中执行(整型)算法操作.
一些变化:
使用后置引用的算术扩展(通常都是和expr一起使用)
z=`expr $z + 3` # 'expr'命令将会执行这个扩展.
使用双括号形式的算术扩展, 也可以使用let命令
后置引用形式的算术扩展已经被双括号形式所替代了 — ((…))和$((…)) — 当然也可以使用非常方便的let结构.
1 z=$(($z+3))
2 z=$((z+3)) # 也正确.
3 # 使用双括号的形式,
4 #+ 参数解引用
5 #+ 是可选的.
6
7 # $((EXPRESSION))是算数表达式. # 不要与命令替换
8 #+ 相混淆.
9
10
11
12 # 使用双括号的形式也可以不用给变量赋值.
13
14 n=0
15 echo "n = $n" # n = 0
16
17 (( n += 1 )) # 递增.
18 # (( $n += 1 )) is incorrect!
19 echo "n = $n" # n = 1
20
21
22 let z=z+3
23 let "z += 3" # 使用引用的形式, 允许在变量赋值的时候存在空格.
24 # 'let'命令事实上执行得的是算术赋值,
25 #+ 而不是算术扩展.