企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
Bourne shell (/bin/sh) 存在于所有的 Unix 系统上,并且用她写的脚本是(完全)可移植的; `man 1 sh` 是一个好的参考。 ## 基础 ### 变量和参数 使用 `variable=value` 的命令格式设置变量,其中 variable 是变量名称,value是打算赋给该变量的值。使用 $variable 获取变量值。 MESSAGE="Hello World"                        # 赋予一个字符串 PI=3.1415                                    # 赋予一个十进制小数N=8 TWON=`expr $N * 2`                           # 算术表达式(只限整数) TWON=$(($N * 2))                             # 另一种语法 TWOPI=`echo "$PI * 2" | bc -l`               # 使用 bc 进行浮点运算 ZERO=`echo "c($PI/4)-sqrt(2)/2" | bc -l` 命令行参数: $0, $1, $2, ...                              # $0 命令本身  $#                                           # 命令参数个数 $*                                           # 所有参数(也可以是 $@) ### 一些特殊的变量 $$                                           # 当前进程 ID $?                                           # 最后命令退出状态码   command  if [ $? != 0 ]; then     echo "command failed"  fimypath=`pwd`mypath=${mypath}/file.txt echo ${mypath##*/}                           # 只显示文件名 echo ${mypath%%.*}                           # 除了扩展名的全路径 var2=${var:=string}                          # 如果var没有被赋值,则string值先赋值给var,                                              # 然后再赋值给var2 ### 结构控制 for file in `ls` do     echo $file done count=0 while [ $count -lt 5 ]; do     echo $count     sleep 1         count=$(($count + 1)) done myfunction() {     find . -type f -name "*.$1" -print       # $1 为方法的第一个参数 } myfunction "txt" #### 产生一个文件 MYHOME=/home/colin cat > testhome.sh << _EOF# 所有_EOF前的代码都会进入到 testhome.sh 文件中去 if [ -d "$MYHOME" ] ; then     echo $MYHOME exists else     echo $MYHOME does not exist fi _EOF sh testhome.sh ## Bourne 脚本实例 来一个小实例,此脚本从本 xhtml 文档创建一个 PDF 小册子: #!/bin/sh# 此脚本可以创建一份供双面打印机打印的 PDF 格式的书 if [ $# -ne 1 ]; then                        # 检查参数是否等于 1   echo 1>&2 "Usage: $0 HtmlFile"     exit 1                                     # 如果不等于1,非0退出 fi file=$1                                      # 文件变量 fname=${file%.*}                             # 文件名变量 fext=${file#*.}                              # 文件扩展名变量 prince $file -o $fname.pdf                   # www.princexml.com pdftops -paper A4 -noshrink $fname.pdf $fname.ps # 创建 postscript 小册子 cat $fname.ps |psbook|psnup -Pa4 -2 |pstops -b "2:0,1U(21cm,29.7cm)" > $fname.book.ps ps2pdf13 -sPAPERSIZE=a4 -sAutoRotatePages=None $fname.book.ps $fname.book.pdf                                                                                    # 在 Windows 上使用 #a4 和 #None! exit 0                                       # exit 0 意为成功 ## 一些 sed 命令 这里是[单行 sed 命令的金矿](http://student.northpark.edu/pemente/sed/sed1line.txt)。还有一个很好的 [sed 介绍及教程](http://www.grymoire.com/Unix/Sed.html)。 sed 's/string1/string2/g'                    # 替换 string1 为 string2 sed -i 's/wroong/wrong/g' *.txt              # 用 g 替换所有返回的单词 sed 's/\(.*\)1/\12/g'                        # 修改 anystring1 为 anystring2 sed '/<p>/,/<\/p>/d' t.xhtml                 # 删除以 <p> 开始,以 </p> 结尾的行 sed '/ *#/d; /^ *$/d'                        # 删除注释和空行 sed 's/[ \t]*$//'                            # 删除行尾空格 (使用 tab 代替 \t) sed 's/^[ \t]*//;s/[ \t]*$//'                # 删除行头尾空格 sed 's/[^*]/[&]/'                            # 括住首字符 [] top -> [t]op sed = file | sed 'N;s/\n/\t/' > file.num     # 为文件添加行号 ## 正则表达式 一些基本的正则表达式同样可用于 sed。作为一个良好的启蒙,可看 [基本正则语法](http://www.regular-expressions.info/reference.html)。 [\^$.|?*+()                          # 特殊字符,其他字符将匹配自身 \                                    # 转义特殊字符,当成普通字符对待 *                                    # 重复前项 0 次或多次 .                                    # 单个字符除换行符 .*                                   # 匹配 0 个或多个字符 ^                                    # 匹配字符串行开始处 $                                    # 匹配字符串行结尾处 .$                                   # 匹配字符串行最后一个字符 ^ $                                  # 匹配单个空格的行 [^A-Z]                               # 匹配任何以 A-Z 字符开始的行 ### 一些实用命令 下列命令对于包含于一个脚本或者单行命令来说很有用。 sort -t. -k1,1n -k2,2n -k3,3n -k4,4n         # 排序 IPv4 格式的 IP 地址 echo 'Test' | tr '[:lower:]' '[:upper:]'     # 转换成大写 echo foo.bar | cut -d . -f 1                 # 返回 foo PID=$(ps | grep script.sh | grep bin | awk '{print $1}')          # 正在运行名为 script 脚本的  PIDPID=$(ps axww | grep [p]ing | awk '{print $1}')                   # ping 的 PID (w/o grep pid) IP=$(ifconfig $INTERFACE | sed '/.*inet addr:/!d;s///;s/ .*//')   # Linux IP=$(ifconfig $INTERFACE | sed '/.*inet /!d;s///;s/ .*//')        # FreeBSD if [ `diff file1 file2 | wc -l` != 0 ]; then [...] fi             # 文件改变了? cat /etc/master.passwd | grep -v root | grep -v \*: | awk -F":" \ # 创建 http passwd '{ printf("%s:%s\n", $1, $2) }' > /usr/local/etc/apache2/passwd testuser=$(cat /usr/local/etc/apache2/passwd | grep -v \    # 查看 passwd 中的用户 root | grep -v \*: | awk -F":" '{ printf("%s\n", $1) }' | grep ^user$) :(){ :|:& };:                                # bash fork 炸弹。会干掉你的机器 tail +2 file > file2                         # 删除文件的第一行 我使用一种小伎俩来一次更改许多文件的扩展名。举个例子,从 .cxx 到 .cpp。排除最后的 `| sh` 先测试一下。你同样可以使用命令 `rename` 来做这些,如果安装了的话。或者使用 bash 内建命令。 # ls *.cxx | awk -F. '{print "mv "$0" "$1".cpp"}' | sh # ls *.c | sed "s/.*/cp & &.$(date "+%Y%m%d")/" | sh # 如 拷贝 *.c 成 *.c.20080401 # rename .cxx .cpp *.cxx                             # 重命名所有 .cxx 成 .cpp # for i in *.cxx; do mv $i ${i%%.cxx}.cpp; done      # bash 内建的