编译为可执行文件?

CFLAGS+=-static shc -r -f script.sh  # 生成script.sh.x二进制文件

basic

-x: 显示脚本执行的顺序
-n: 不运行,只检查语法

#!/bin/sh
#!/bin/bash
#!/usr/bin/make

# variable
# 注意: 默认的变量类型都是字符串!单引号中的变量不会扩展!
# 变量只能字母开头,若中间有空格需使用引号! 注意: 两边不能有空格!
  set -e  # 后面的脚本语句有任何一个错误(不返回0)就直接退出!
  declare -i sum=1+2+3  # -a:数组;-x:将变量设为环境变量,+x:取消;-r:readonly
  age=22; age=${age}+1  # 结果为'22+1'
  unset age   # 清除变量,unset b[2]删除第3个元素

# array
  a=()  # 定义一个空数组
  a=(${a[@]} 'newitem')  # 追加元素,单引号双引号都行
  a[1]=2  # 修改第2个元素为2
  a[5]=3  # 若下标5越界则自动追加到最后一个索引.但在此使用a[5]操作时仍然操作的是最后一个追加的元素而不是继续追加!
  unset a[5]  # 删除元素
  a=($(seq 100)) # 1~100; 'echo $a'会显示1,即类似于C的数组!
  a=((${a} 101)) # 追加元素
  b=("tom" john) # 1个数组,里面存放3个字符串
  echo ${b[*]}   # 显示所有,访问整个数组则为: ${b[@]}
  echo ${#a[@]}  # 100,数组的元素个数(#a[2]表第3个元素占几个字符),也可吧'@'换成'*'!
  echo ${16#1a}  # 26,十六进制1a转化为10进制
  c=(${a[@]:98:2})  # '99 100',:索引:个数,不指定个数表后面所有!不指定起始则0开始!索引也可是负数表示倒数第几个!
  c=(${a[@]:value:newvalue})  # 模式替换

string

operationfunction
${var=str}若var未定义,则返回str并将var赋值为str.其他情况返回$var.
${var:=str}若var未定义或为空,则返回str并将var赋值为str.其他情况返回$var.
${var?str}若var未定义,则将str写入stderr,本语句失败!其他情况返回$var.
${var:?str}若var未定义或为空,则将str写入stderr,本语句失败!其他情况返回$var.
${var-str}若var未定义,则返回str.否则返回$var.
${var:-str}若var未定义或为空,则返回str.否则返回$var.
${var+str}若var已定义(也可为空),则返回str.未定义时则返回空,如空字符串!
${var:+str}若var已定义且非空,则返回str.空值或未定义则返回空,如空字符串!
${var:0:2}索引+个数,此处是提取最左边的2个字符!
以下操作符的#、%来配合通配符!! 表示仅操作通配符所匹配的文本!
${var#*str}从左到右搜索,删除该最短匹配,返回删除后的子串!
${var##s*r}从左到右搜索,删除该最长匹配,返回删除后的子串! extension="${filepath##*.}"
${var%str*}从右到左搜索,删除该最短匹配,返回删除后的子串! filename="${filepath%.*}"
${var%%s*r}从右到左搜索,删除该最长匹配,返回删除后的子串!
${var/s/r}从左至右搜索str替换所有str为r,返回替换后的整体结果!不写r即是删除!
${var/s/r}从右到左搜索最短匹配s替换为r,返回替换后的整体结果!
${var//s/r}从右到左搜索最长匹配s替换为r,返回替换后的整体结果!请类比其他

case

  • break
    类似于C中的break
    比C的switch更复杂: 条件分支支持字符串
    每个分支还可以有三个选项: break、无条件继续(;&)、有条件继续(;;&)
    其中后两者需要bash4.1以上的版本($BASH_VERSION)!
  • 分支条件
    必须以右括号结尾,可以使用方括号等正则表达式的形式:
    *(任意字串) ?(任意字符)
    [abc](abc中的任意一个) [a-n](a-n任意一个) |(或)
    最后一分支条件类似于default(没有匹配项)使用*)表示
  • 分支命令
    必须以双分号结尾,但最后一个可以不加;;
  case "$var" in
  [yY]|[Yy][Ee][Ss])
    echo "Good Morning";;
  *)
    echo "Sorry,not recognized!"
    exit 1
  esac

function

  • 函数的退出码
    为最后一条命令的退出状态码.因此无法知道其他语句是否成功!
    可以使用return命令来指定退出码,此时$?返回的就是该值.但注意,其范围在[0,255]
  • 函数的输出
    可以使用echo来定制函数输出,然后`var=``funame param1..```来接收输出.
    注意与退出状态的区分!退出状态是函数return的或最后一条语句的执行状态,且其值有范围.
  • 函数库文件
    定义一个里面全是函数脚本共其他脚本使用,不是看起来那么简单,因为shell本质是启动一个进程来执行脚本文件.
    如果不想另起进程,应该使用source命令(可用.来替代)
    exec也不会产生新的,但它会关闭当前的shell的进程.
    . ../funcs.sh: 读取并执行上层目录中的脚本,以便导入其中的变量和函数!
  # '$#'表参数个数; '$1'表示参数1...注意与脚本变量区分,这些跳到函数外就变成了脚本的变量!
  # 默认情况下,函数内可以尽情访问函数外的变量,但一般不这么做.使用local定义局部最好!
  # 注意: 向函数传递数组变量只会传递第一个元素,应该把数组解开当作所有参数传递(在函数内部再把所有参数构造起来)
  function factorial { # 也可以直接'factorial() {}'定义 
    local newarray
    newarray=(`echo "$@"`)  # $@就是解包元素组后的所有元素
    echo ${newarray[*]}  # 返回数组的方式
    # 函数是可以调用自己的`fractorial $tmp`
  }

  function finish {
    # 类比于finally
    # 收尾代码,比如要删除的一些临时目录
    # 或者是一些必须执行的代码,如无论后面如何,都启动服务
    sudo service xxx start
  }

  trap finish EXIT
  sudo service xxx stop

sleep

  # 默认以秒为单位,支持小数
  # usleep以微秒为单位即10^-6
  sleep 0.8s  # 可不加s
  sleep 0.8m  # 分钟
  sleep 0.8h  # 小时
  sleep 0.8d  # 天

read

# 读取以空格为分割的两个输入,分别赋值给var1,var2;若输入多余2个,则余下的所有均赋值给var2
read var1 var2

# 提示用户输入;30内有效的输入会赋给变量var,否则略过该语句;可以加上-s参数,用户输入将不可见!
read -p "please input your name" -t 30 var

# 限定只取一个字符,不用用户回车了
read -n 1 var

# -e:会对\n等字符做转换而不是当成纯字符.-n:不要换行了(默认会给字符串加上换行)
echo -en '1.\tFirst'

# 下面颜色echo+read来生成选择菜单!
function menu {
	clear;echo
	echo -e "\t\t\tSys Admin Menu\n"
	echo -e "\t1. Display disk space\n"
	echo -e "\t2. Display memory usage\n"
	echo -en "\t\tEnter option: "
	read -n 1 option
}

case $option in
1) diskspace;; # 调用某个函数
2) memoryusage;;
*) echo "Sorry,wrong option";;
esac

getopts

  • bash内部命令
    不同于getopt; 注意getopts解析后会移除选项前的-号!
    如果选项值要包含空格请使用双引号括起来!
  • $OPTIND
    表正在处理第几个选项(从1开始),每处理完一个该值就会+1
    所以可以在循环处理后shift $[ $OPTIND-1 ]来移动到第1个参数(注意区别于选项)
  • $OPTARG
    如果一个选项需要选项值并且传递了,则表示该选项的选项值.
    如果一个选项需要选项值却没给,且optstring前端有冒号,则getopts将解析出’:’,OPTARG表该选项的选项名!如果一个选项需要选项值却没给,optstring前端无冒号,getopts将解析?,OPTARG表该选项的选项名! 如果一个选项需要选项值却没给,但optstring前端无冒号,则getopts将解析出'?',OPTARG表该选项的选项名! 如果未识别该选项,则getopts将解析出?,$OPTARG表该选项的选项名!

getopts optstring parameter

if [ $# -lt 1 ]; then
	echo "there is no option";
else
	while getopts ":Iti:s:v" opt; do
		case $opt in
		I) echo "option is I ";;
		t) echo "option is t ";;
		i) echo "option is i,the value is $OPTARG";;
		s) echo "option is s,the value is $OPTARG";;
		v) echo "option is v\n";;
		:) echo "Error: '-$OPTARG' requires an argument";;
		?) echo "Error: '-$OPTARG' not supported!";;
		esac
	done
fi

select

将in后的列表列成一个表单,提示用户选择
用户选择后,var便具有值,并执行statements

select option in "Display disk space" "Display memory usage"; do
	case $option in
	"Display disk space") diskspace;;
	"Display memory usage") memoryusage;;
	*) clear
	esac
done

dialog

其输出一般使用退出码$?或STDERR; dialog [--option] --widget parameter

# --default-item string: 指定一些选单控件的默认选项
# --insecure: 在passwordbox控件键入时显示星号.
# --tab-len n: 指定一个tab占用的空格数,默认是8.
# --output-fd fd: 指定输出,而不是STDERR.
# --title title: 指定对话框的文本!
# widgets: calendar checklist form fselect gauge infobox inputbox inputmenu menu msgbox pause passwordbox passwordform radiobox tailbox tailboxbg textbox timebox yesno

# menu :20x10维度,窗口中显示8个item.选定菜单的文本会被发送到STDERR.
dialog --menu "title msg" 10 20 8 1 "first-item" "" 2 "second-item" 2>select.txt

# msgbox :最下方只有1个OK按钮,上方就是一个Edit.如果要显示文件的内容应使用textbox.
dialog --msgbox hello 10 20 #height,width
dialog --yesno "hello world" 10 20 #--defaultno可以将默认答案设为no

# textbox :与msgbox一样,只有1个Exit按钮,上方就是一个大的RichEdit.
dialog --textbox /etc/passwd 10 20

# inputbox :提示文本的下方会出现输入框
dialog --inputbox "Enter your age:" 10 20 2>age.txt

# filedialog :文件选择对话框,一次只能选定1个.
dialog --fselect $HOME/ 10 20 2>file.txt

tr

translate or delete characters

用来去除或替换重复的字符,相当于sed的y命令!

  • 注意: 并不是字符串整体替换而是单个字符一一对应替换!
  • 如果set1个数多,则将多出的字符全部替换为set2最后一个字符!
  • tr [a-z] [A-Z]: 将每个字符大写. [0-9]表数字.
  • [a*2]: 表匹配aa字符串

-d: 删除出现在序列中的每一个字符!如删除文件中所有出现h,e,l,o的字符: -d "hello"
-s: 替换出现在source字符序列中的每一个字符为replace中对应的字符.source中多出的则均映射到replace中最后一个字符! 注意如果某个字符重复出现则只替换成1个!如删除多余的空行: sed -s "\n" <file
-t: 与-s类似,但source中多出的字符会被忽略!
-c: 将source之外的所有字符都替换为replace中对应的字符,source多出的则均映射到replace的最后一个字符.
tr [options] source replace < file

gnome

  • KDE提供了Kdialog包, gnome提供了Gdialogzenity.
  • 它们会将结果返回到STDOUT中,如calendar选择的日期、file-selection选择的路径…

zenity --wiget --option1 optval --option2 optval

# --file-selection: 文件或路径选择对话框
# --notification:   通知图标
# --text-info: 含有文本的文本框.
# --question:  yesno对话框
# --progress:  进度条对话框
# --calendar:  日历
# --scale: 显示可调大小的窗口
# --entry: 文本输入对话框
# --error: 错误对话框
# --list:  列表对话框
zenity --info --title 'title' --text 'content'