加载中...

脚本


Bourne shell (/bin/sh) 存在于所有的 Unix 系统上,并且用她写的脚本是(完全)可移植的; man 1 sh 是一个好的参考。

基础

变量和参数

使用 variable=value 的命令格式设置变量,其中 variable 是变量名称,value是打算赋给该变量的值。使用 $variable 获取变量值。

  1. MESSAGE="Hello World"                        # 赋予一个字符串
  2. PI=3.1415                                    # 赋予一个十进制小数N=8
  3. TWON=`expr $N * 2`                           # 算术表达式(只限整数)
  4. TWON=$(($N * 2))                             # 另一种语法
  5. TWOPI=`echo "$PI * 2" | bc -l`               # 使用 bc 进行浮点运算
  6. ZERO=`echo "c($PI/4)-sqrt(2)/2" | bc -l`

命令行参数:

  1. $0, $1, $2, ...                              # $0 命令本身 
  2. $#                                           # 命令参数个数
  3. $*                                           # 所有参数(也可以是 $@)

一些特殊的变量

  1. $$                                           # 当前进程 ID
  2. $?                                           # 最后命令退出状态码
  3.   command  if [ $? != 0 ]; then
  4.     echo "command failed"  fimypath=`pwd`mypath=${mypath}/file.txt
  5. echo ${mypath##*/}                           # 只显示文件名
  6. echo ${mypath%%.*}                           # 除了扩展名的全路径
  7. var2=${var:=string}                          # 如果var没有被赋值,则string值先赋值给var,
  8.                                              # 然后再赋值给var2

结构控制

  1. for file in `ls`
  2. do
  3.     echo $file
  4. done
  5. count=0
  6. while [ $count -lt 5 ]; do
  7.     echo $count
  8.     sleep 1    
  9.     count=$(($count + 1))
  10. done
  11. myfunction() {
  12.     find . -type f -name "*.$1" -print       # $1 为方法的第一个参数
  13. }
  14. myfunction "txt"

产生一个文件

  1. MYHOME=/home/colin
  2. cat > testhome.sh << _EOF# 所有_EOF前的代码都会进入到 testhome.sh 文件中去
  3. if [ -"$MYHOME" ] ; then
  4.     echo $MYHOME exists
  5. else
  6.     echo $MYHOME does not exist
  7. fi
  8. _EOF
  9. sh testhome.sh

Bourne 脚本实例

来一个小实例,此脚本从本 xhtml 文档创建一个 PDF 小册子:

  1. #!/bin/sh# 此脚本可以创建一份供双面打印机打印的 PDF 格式的书
  2. if [ $# -ne 1 ]; then                        # 检查参数是否等于 1
  3.   echo 1>&2 "Usage: $0 HtmlFile"  
  4.   exit 1                                     # 如果不等于1,非0退出
  5. fi
  6. file=$1                                      # 文件变量
  7. fname=${file%.*}                             # 文件名变量
  8. fext=${file#*.}                              # 文件扩展名变量
  9. prince $file -o $fname.pdf                   # www.princexml.com
  10. pdftops -paper A4 -noshrink $fname.pdf $fname.ps # 创建 postscript 小册子
  11. cat $fname.ps |psbook|psnup -Pa4 -2 |pstops -"2:0,1U(21cm,29.7cm)" > $fname.book.ps
  12. ps2pdf13 -sPAPERSIZE=a4 -sAutoRotatePages=None $fname.book.ps $fname.book.pdf                                                                                    # 在 Windows 上使用 #a4 和 #None!
  13. exit 0                                       # exit 0 意为成功

一些 sed 命令

这里是单行 sed 命令的金矿。还有一个很好的 sed 介绍及教程。

  1. sed 's/string1/string2/g'                    # 替换 string1 为 string2
  2. sed -'s/wroong/wrong/g' *.txt              # 用 g 替换所有返回的单词
  3. sed 's/\(.*\)1/\12/g'                        # 修改 anystring1 为 anystring2
  4. sed '/<p>/,/<\/p>/d' t.xhtml                 # 删除以 <p> 开始,以 </p> 结尾的行
  5. sed '/ *#/d; /^ *$/d'                        # 删除注释和空行
  6. sed 's/[ \t]*$//'                            # 删除行尾空格 (使用 tab 代替 \t)
  7. sed 's/^[ \t]*//;s/[ \t]*$//'                # 删除行头尾空格
  8. sed 's/[^*]/[&]/'                            # 括住首字符 [] top -> [t]op
  9. sed = file | sed 'N;s/\n/\t/' > file.num     # 为文件添加行号

正则表达式

一些基本的正则表达式同样可用于 sed。作为一个良好的启蒙,可看 基本正则语法。

  1. [\^$.|?*+()                          # 特殊字符,其他字符将匹配自身
  2. \                                    # 转义特殊字符,当成普通字符对待
  3. *                                    # 重复前项 0 次或多次
  4. .                                    # 单个字符除换行符
  5. .*                                   # 匹配 0 个或多个字符
  6. ^                                    # 匹配字符串行开始处
  7. $                                    # 匹配字符串行结尾处
  8. .$                                   # 匹配字符串行最后一个字符
  9. ^ $                                  # 匹配单个空格的行
  10. [^A-Z]                               # 匹配任何以 A-Z 字符开始的行

一些实用命令

下列命令对于包含于一个脚本或者单行命令来说很有用。

  1. sort -t. -k1,1n -k2,2n -k3,3n -k4,4n         # 排序 IPv4 格式的 IP 地址
  2. echo 'Test' | tr '[:lower:]' '[:upper:]'     # 转换成大写
  3. echo foo.bar | cut -. -1                 # 返回 foo
  4. PID=$(ps | grep script.sh | grep bin | awk '{print $1}')          # 正在运行名为 script 脚本的 
  5. PIDPID=$(ps axww | grep [p]ing | awk '{print $1}')                   # ping 的 PID (w/o grep pid)
  6. IP=$(ifconfig $INTERFACE | sed '/.*inet addr:/!d;s///;s/ .*//')   # Linux
  7. IP=$(ifconfig $INTERFACE | sed '/.*inet /!d;s///;s/ .*//')        # FreeBSD
  8. if [ `diff file1 file2 | wc -l` != 0 ]; then [...] fi             # 文件改变了?
  9. cat /etc/master.passwd | grep -v root | grep -v \*: | awk -F":" \ # 创建 http passwd
  10. '{ printf("%s:%s\n", $1, $2) }' > /usr/local/etc/apache2/passwd
  11. testuser=$(cat /usr/local/etc/apache2/passwd | grep -v \    # 查看 passwd 中的用户
  12. root | grep -v \*: | awk -F":" '{ printf("%s\n", $1) }' | grep ^user$)
  13. :(){ :|:& };:                                # bash fork 炸弹。会干掉你的机器
  14. tail +2 file > file2                         # 删除文件的第一行

我使用一种小伎俩来一次更改许多文件的扩展名。举个例子,从 .cxx 到 .cpp。排除最后的 | sh 先测试一下。你同样可以使用命令 rename 来做这些,如果安装了的话。或者使用 bash 内建命令。

  1. # ls *.cxx | awk -F. '{print "mv "$0" "$1".cpp"}' | sh
  2. # ls *.c | sed "s/.*/cp & &.$(date "+%Y%m%d")/" | sh # 如 拷贝 *.c 成 *.c.20080401
  3. # rename .cxx .cpp *.cxx                             # 重命名所有 .cxx 成 .cpp
  4. # for i in *.cxx; do mv $i ${i%%.cxx}.cpp; done      # bash 内建的

还没有评论.