分类:
2010-01-03 22:43:04
摘自《高级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=`注:不要将一个长文本文件的全部内容设置到变量中, 除非你有一个非常好的原因非这么做不可, 也不要将二进制文件的内容保存到变量中, 即使是开玩笑也不行.
变量替换允许将一个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 #include2 3 /* "Hello, world." C program */ 4 5 int main() 6 { 7 printf( "Hello, world." ); 8 return (0); 9 } bash$ gcc -o hello hello.c1 #!/bin/bash 2 # hello.sh 3 4 greeting=`./hello` 5 echo $greetingbash$ 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 #+ 而不是算术扩展.