bash入门教程

jopen 10年前
shell的种类:
sh  - Bourne shell
csh or tcsh - C shell
korn - Korn shell
bash - GNU Bourne-Again shell

1.最简单的列子
例子
#!/bin/bash  
# This is a very simple example echo Hello World
echo Hello World

解释:
在 BASH 中 第一行的 "#!" 及后面的 "/bin/bash" 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。
在 BASH 程序中从“#”号(注意:后面紧接着是“!”号的除外)开始到行尾的多有部分均被看作是程序的注释
echo 语句的功能是把 echo 后面的字符串输出到标准输出中去

执行该程序:
1.$ bash hello 或 
   $ sh hello 
2.将 hello 文件改为可以执行的文件,然后直接运行它,此时由于 hello 文件第一行的 "#! /bin/bash" 的作用,系统会自动用/bin/bash 程序去解释执行 hello 文件的:
$ chmod u+x hello 
$ ./hello

2.关于输入、输出和错误输出 
在 Linux 系统中:
标准输入(stdin)默认为键盘输入;
标准输出(stdout)默认为屏幕输出;
标准错误输出(stderr)默认也是输出到屏幕(上面的 std 表示 standard)。

$ ls > ls_result 
$ ls -l >> ls_result 
ls 命令的结果输出 重定向到 ls_result 文件中和 追加到 ls_result 文件中,而不是输出到屏幕上。
">"就是输出(标准输出和标准错误输出)重定向的代表符号,连续两个 ">" 符号,即 ">>" 则表示不清除原来的而追加输出

$ find /home -name lost* 2> err_result 
这个命令在 ">" 符号之前多了一个 "2","2>" 表示将标准错误输出重定向。由于 /home 目录下有些目录由于权限限制不能访问,因此会产生一些标准错误输出被存放在 err_result 文件中

$ find /home -name lost* > all_result 2>& 1 
首先将标准错误输出也重定向到标准输出中,再将标准输出重定向到 all_result 这个文件中。这样我们就可以将所有的输出都存储到文件中了
更简单的写法:
$ find /home -name lost* >& all_result 
可以让你避开众多无用出错信息的干扰:
$ find /home -name lost* 2> /dev/null

另外一个非常有用的重定向操作符是 "-"
$ (cd /source/directory && tar cf - . ) | (cd /dest/directory && tar xvfp -)  
该命令表示把 /source/directory 目录下的所有文件通过压缩和解压,快速的全部移动到 /dest/directory 目录下去

3.变量
例子:
#!/bin/bash  
# give the initialize value to 
STR STR="Hello World"  
echo $STR

注意点:
1,变量赋值时,'='左右两边都不能有空格;
2,BASH 中的语句结尾不需要分号(";"); 
3,除了在变量赋值和在FOR循环语句头中,BASH 中的变量使用必须在变量前加"$"符号,
4,由于 BASH 程序是在一个新的进程中运行的,所以该程序中的变量定义和赋值不会改变其他进程或原始 Shell 中同名变量的值,也不会影响他们的运行。

一个变量即可以被定义为一个字符串,也可以被再定义为整数。如果对该变量进行整数运算,他就被解释为整数;如果对他进行字符串操作,他就被看作为一个字符串
例子:
#!/bin/bash  
x=1999  
let "x = $x + 1"  
echo $x  
x="olympic'"$x  
echo $x

整数运算一般通过 let 和 expr 这两个指令来实现,如对变量 x 加 1 可以写作:let "x = $x + 1" 或者 x=`expr $x + 1`

对应的操作
整数操作
字符串操作
相同
-eq
=
不同
-ne
!=
大于
-gt
>
小于
-lt
<
大于或等于
-ge

小于或等于
-le

为空

-z
不为空

-n

BASH 中用于判断文件属性的操作符:
运算符
含义( 满足下面要求时返回 TRUE )
-e file
文件 file 已经存在
-f file
文件 file 是普通文件
-s file
文件 file 大小不为零  
-d file
文件 file 是一个目录   
-r file
文件 file 对当前用户可以读取   
-w file
文件 file 对当前用户可以写入
-x file
文件 file 对当前用户可以执行   
 -g file
文件 file 的 GID 标志被设置   
-u file
文件 file 的 UID 标志被设置   
-O file
 文件 file 是属于当前用户的   
-G file
文件 file 的组 ID 和当前用户相同
file1 -nt file2   
文件 file1 比 file2 更新
file1 -ot file2 
文件 file1 比 file2 更老   

局部变量
在变量首次被赋初值时加上 local 关键字就可以声明一个局部变量
例子:
#!/bin/bash  
HELLO=Hello  
function hello {  
   local HELLO=World    
  echo $HELLO 
 }  
echo $HELLO  
hello  
echo $HELLO 
该程序的执行结果是: 
Hello 
World 
Hello

4.基本流程控制语法
if...then...else 
if 语句用于判断和分支,其语法规则和 C 语言的 if 非常相似。其几种基本结构为:  
if [ expression ] 
then 
  statments 
fi  
或者==========================   
if [ expression ] 
then 
  statments 
else 
  statments 
fi  
或者==========================   
if [ expression ] 
then 
  statments 
else if [ expression ]  
     then  
        statments   
     else 
    statments  
fi  
或者==========================   
if [ expression ] 
then 
  statments 
elif [ expression ]   
then 
    statments   
else 
    statments 
fi

注:如果你将 if 和 then 简洁的写在一行里面,就必须在 then 前面加上分号,如:if [ expression ]; then ... 

for循环
for $var in [list] 
do 
  statments 
done
注:do 和 for 被写在同一行,必须在 do 前面加上 ";"。如: for $var in [list]; do

例子:
#!/bin/bash   
for day in Sun Mon Tue Wed Thu Fri Sat  
do  
  echo $day 
done

如果列表被包含在一对双引号中,则被认为是一个元素
例子:
#!/bin/bash   
for day in  “Sun Mon Tue Wed Thu Fri Sat “ 
do  
  echo $day 
done

如果写成 for day 而没有后面的 in [list] 部分,则 day 将取遍命令行的所有参数
例子:
#!/bin/bash   
for param  
do  
  echo $param  
done   
exit 0 

while
while [ condition ] 
do 
  statments 
done

util
until [ condition is TRUE ] 
do 
  statments 
done 

case
case "$var" in  
    condition1 )   
         statments1;;  
    condition2 )  
         statments2;;
      ...  
     * ) 
          default statments;; 
esac

例子
#!/bin/bash   
echo "Hit a key, then hit return."  
read Keypress   
case "$Keypress" in  
     [a-z] ) echo "Lowercase letter";;  
     [A-Z] ) echo "Uppercase letter";;   
     [0-9] ) echo "Digit";;  
 * ) echo "Punctuation, whitespace, or other";;  
esac   
exit 0
"read Keypress" 一句中的 read 语句表示从键盘上读取输入

支持break/continue
你懂得

5.函数
function my_funcname { 
   code block 
 或者  
my_funcname() {
   code block 
BASH 中函数参数的定义并不需要在函数定义处就制定,而只需要在函数被调用时用 BASH 的保留变量 $1 $2 ... 来引用就可以了;
BASH 的返回值可以用 return 语句来指定返回一个特定的整数,如果没有 return 语句显式的返回一个返回值,则返回值就是该函数最后一条语句执行的结果(一般为 0,如果执行失败返回错误码)。
函数的返回值在调用该函数的程序体中通过 $? 保留字来获得。
例子
#!/bin/bash
square() {
 let "res = $1 * $1"
 return $res  
}
square $1
result=$?
echo $result
exit 0


6.BASH 中的特殊保留字
保留变量
$IFS  这个变量中保存了用于分割输入参数的分割字符,默认是空格。  
$HOME  这个变量中存储了当前用户的根目录路径。  
$PATH  这个变量中存储了当前 Shell 的默认路径字符串。  
$PS1  表示第一个系统提示符。  
$PS2  表示的二个系统提示符。 
$PWD  表示当前工作路径。  
$EDITOR 表示系统的默认编辑器名称。  
$BASH  表示当前 Shell 的路径字符串。 
$0, $1, $2, ...  表示系统传给脚本程序或脚本程序传给函数的第0个、第一个、第二个等参数。 
$#   表示脚本程序的命令参数个数或函数的参数个数。 
$$   表示该脚本程序的进程号,常用于生成文件名唯一的临时文件。  
$?   表示脚本程序或函数的返回状态值,正常为 0,否则为非零的错误号。
$*   表示所有的脚本参数或函数参数。 
$@   和 $* 涵义相似,但是比 $* 更安全。 
$!   表示最近一个在后台运行的进程的进程号。

随机数
$RANDOM:随机产生一个大小在 1 到 65536 之间的整数。

变量的特殊操作
${var-default} 表示如果变量 $var 还没有设置,则保持 $var 没有设置的状态,并返回后面的默认值 default。 
${var=default} 表示如果变量 $var 还没有设置,则取后面的默认值 default。  
${var+otherwise} 表示如果变量 $var 已经设置,则返回 otherwise 的值,否则返回空( null )。 
${var?err_msg} 表示如果变量 $var 已经设置,则返回该变量的值,否则将后面的 err_msg 输出到标准错误输出上。
这些用法主要用于从文件路径字符串中提取有用信息: 
${var#pattern}, ${var##pattern} 用于从变量 $var 中剥去最短(最长)的和 pattern 相匹配的最左侧的串。 
${var%pattern}, ${var%%pattern} 用于从变量 $var 中剥去最短(最长)的和 pattern 相匹配的最右侧的串。 
另外 BASH 2 中还加入下面一些操作: 
${var:pos} 表示去掉变量 $var 中前 pos 个字符。 
${var:pos:len} 表示变量 $var 中去掉前 pos 个字符后的剩余字符串的前 len 个字符。 
${var/pattern/replacement} 表示将变量 $var 中第一个出现的 pattern 模式替换为 replacement 字符串。 
${var//pattern/replacement} 表示将变量 $var 中出现的所有 pattern 模式全部都替换为 replacment 字符串。


7.BASH 中的其他高级问题
BASH 中对返回值的处理
无论是在 Shell 中对 BASH 脚本返回值的处理,还是在脚本中对函数返回值的处理,都是通过 "$?" 系统变量来获得。
BASH 要求返回值必须为一个整数,不能用 return 语句返回字符串变量

用 BASH 设计简单用户界面
select var in [list] 
do 
 statments use $var 
done
BASH 会将 [list] 中的所有项加上数字列在屏幕上等待用户选择,在用户作出选择后,变量 $var 中就包含了那个被选中的字符串
例子
#!/bin/bash   
OPTIONS="Hello Quit"  
select opt in $OPTIONS; do  
     if [ "$opt" = "Quit" ]; then    
        echo done    
        exit  
     elif [ "$opt" = "Hello" ]; then    
            echo Hello World    
        else     
            clear  
            echo bad option   
    fi  
done   
exit 0

BASH 程序的调试
用 bash -x bash-script 命令,可以查看一个出错的 BASH 脚本到底错在什么地方,可以帮助程序员找出脚本中的错误。 
另外用 trap 语句可以在 BASH 脚本出错退出时打印出一些变量的值,以供程序员检查。
trap 语句必须作为继 "#!/bin/bash" 后的第一句非注释代码,一般 trap 命令被写作: trap 'message $checkvar1 $checkvar2' EXIT