Shell & Tools

 

${}

利用${ }还可针对不同的变数状态赋值(沒设定、空值、非空值):

  • ${var-myvar} 假如$var沒有设定,則使用myvar作返回值,空值及非空值时不作处理
  • ${var:-myvar} 假如$var沒有设定或为空值,則使用myvar作返回值,非空值时不作处理
  • ${var+myvar} 假如$var設为空值或非空值,均使用myvar作返回值,沒设定时不作处理
  • ${var:+myvar} 若$var为非空值,則使用myvar作返回值,沒设定及空值时不作处理
  • ${var=myvar} 若$var沒设定,則使用myvar作返回值,同时将$var赋值为myvar,空值及非空值时不作处理
  • ${var:=myvar} 若$var沒设定或为空值,則使用myvar作返回值,同时将$var 赋值为myvar,非空值时不作处理
  • ${var?myvar} 若$var沒设定,則将myvar輸出至STDERR,空值及非空值时不作处理
  • ${var:?myvar} 若$var没设定或为空值,则将myvar输出至STDERR,非空值时不作处理

使用频次比较高的用法为${var:+myvar},一般用在shell可选的参数中,例如:

param=
# equal to script.sh other_params 
script.sh ${param:+"--param $param"} other_params

shell program

  • $*引用所有参数, $#存放参数的个数, $0引用程序名, $i第i个参数
  • 数学计算
$ var=1+1 error # error,"1+1"
$ let var+=1 | let "var+=1"
$ var=`expr $var + 1` 
$ ((var+=1)) 
$ var=$[$var+1] #自己推荐使用这个哈

数组

a=(1 2 3 4 5)   #() 数组
a[1] = 100      #赋值
echo ${#a[*]}   #length
echo ${a[*]}    #all element
c=(${a[@]:1:4}) #${数组名[@或*]:起始位置:长度} 切片原先数组  

括号 () {}

() 为了在子shell中执行一组命令,可以用命令分隔符(即”,”)隔开每一个命令,并把所有的命令用圆括号()括起来。 {} 如果使用{}来代替(),那么相应的命令将在当前shell中作为一个整体被执行

字符串

| 表达式                           | 含义                                                                          |
|----------------------------------+-------------------------------------------------------------------------------|
| ${#string}                       | $string的长度                                                                 |
| ${string:position}               | 在$string中, 从位置$position开始提取子串                                      |
| ${string:position:length}        | 在$string中, 从位置$position开始提取长度为$length的子串                       |
| ${string#substring}              | 从变量$string的开头, 删除最短匹配$substring的子串                             |
| ${string##substring}             | 从变量$string的开头, 删除最长匹配$substring的子串                             |
| ${string%substring}              | 从变量$string的结尾, 删除最短匹配$substring的子串                             |
| ${string%%substring}             | 从变量$string的结尾, 删除最长匹配$substring的子串                             |
| ${string/substring/replacement}  | 使用$replacement, 来代替第一个匹配的$substring                                |
| ${string//substring/replacement} | 使用$replacement, 代替所有匹配的$substring                                    |
| ${string/#substring/replacement} | 如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring |
| ${string/%substring/replacement} | 如果$string的后缀匹配$substring, 那么就用$replacemen                          |

sed

  • -e 连续执行多个编辑
sed -e "s:aa:bb:" -e "s:\d::" file
  • -i 在源文件上进行替换
#如删除windows下文件的^M显示
sed -i 's/^M//g' filename 
  • ()表示分组,_1,_2引用,标准正则表达式使用()
#如根据路径取x.wav的文件名
sed "s:.*/\(.*\)\.wav:\1:"

grep

  • -P perl形式的正则表达式
  • -v 不匹配的项
  • -H 显示文件名
  • -f 从文件中取得模式
  • -i 忽略大小写

cut(default tab)

#-d分割符, -f域
$ cut -d' ' -f2

tr

  • 只接收标准输入
  • tr set1 set2
  • tr “ “ “\n” 将空格换成回车
  • tr “a-z” “A-Z” 或者 tr [:lower:] [:upper:] 大小写转换
  • tr -s “ “ 将多个空格替换为1个
  • tr -d 删除, tr -cd ‘[a-z]’
  • tr -sc ‘a-z’ ‘\n’, -c取不是’a-z’, 所以将不是a-z的字符替换为换行

find

  • -L 包含链接文件,默认不查找链接文件
  • -name 文件名
  • -type (f d l)
  • -mmin 最近修改时间
  • -maxdepth
$ find -L . -name "*.sh" -type f

awk

  • 以awk文件方式运行, -f
#!/bin/awk
{print $0}
awk -f strcat.awk if.sh
  • 字符串连接 a (“” ”+”) b
  • print printf
{print $0}
{printf("%04d %s", NR, $0)} 
  • -v 可带输入变量
awk -v num=10 '{print num}'
  • 关联数组
#!/bin/awk
#word count
BEGIN {
	FS="[^a-zA-Z]"
}
{
	for(i=1; i<=NF; i++)
		words[tolower($i)]++;
}
END {
	delete words[""]
	for (x in words)
		print x, words[x];
}
  • getline close(在脚本中要两次读取同一文件时要close)
#将拼音级的抄本查表转换成音素级抄本
#!/bin/bash

if [ $# -ne 2 ]; then
	echo "Usage: pinyin2phone.sh dict_file pinyin2phone"
	exit -1
fi

dict=$1
awk -v phone_map=$2 \
'BEGIN {
	while (getline < phone_map) {
		t = "";
		for (i=2; i<=NF; i++)
			t = t " " $i;
		map[$1] = t;
		#print $1, t
	}
    close(phone_map) #此处也可以不写
}
{
	line = $1;
	for (i=2; i<=NF; i++)
		line = line " " map[$i];
	print line;
}
' $dict 
  • 字符串处理函数
gsub(r,s)    在整个$0中用s替代r
gsub(r,s,t)    在整个t中用s替代r
index(s,t)    返回s中字符串t的第一位置
length(s)    返回s长度
match(s,r)    测试s是否包含匹配r的字符串
split(s,a,fs)    在fs上将s分成序列a
sprint(fmt,exp)    返回经fmt格式化后的exp
sub(r,s)$0中最左边最长的子串代替s
substr(s,p)    返回字符串s中从p开始的后缀部分
substr(s,p,n)    返回字符串s中从p开始长度为n的后缀部分
#仅仅使用begin在shell中格式化字符串
awk x=10 'BEGIN{printf("S%04d", x)}'
awk 'BEGIN{print split("123#456#678", myarray, "#")}'
awk '{BEGIN {print match("ANCD", /d/)}'
  • system,调用shell命令
#function system(expr) uses /bin/sh to execute expr and returns the exit status of the command expr.
#假设文件file中每一行均为文件名,cat所有文件
$ awk '{system("cat" " "  $0)}' file
  • 莫给NR,NF加$,经常犯这个错
  • other example
# emulate cat.

     { print }

# emulate wc.

     { chars += length($0) + 1  # add one for the \n
       words += NF
     }

     END{ print NR, words, chars }

BRE vs ERE

Basic vs Extended Regular Expressions In basic regular expressions the meta-characters ?, +, {, |, (, and ) lose their special meaning; instead use the backslashed versions \?, +, {, |, (, and )

  • 注意与linux命令中通配符区分 其在命令中表示任意字符重复任意次
  • grep sed awk均使用BRE,grep在-E选项时可使用ERE
  • 所以sed “:./(.).wav:\1:”就比较好理解了