C初级知识(三)

# 用户在命令行输入命令后,一般情况下SHELL后fork并exec该命令。但是Shell的内建命令例外,执行内建命令相当于调用Shell中的一个函数,并不创建新的进程。
# 但如果将命令行下输入的命令用()括起来,那么也会fork出一个子shell执行小括号中的命令。

# 1,Shell文件名代换(Globbing)  : *?[]

##  * 0个或0个任意字符
##  ? 一个任意字符
##  [] 匹配方括号中任意一个字符的一次出现

# 2,命令代换:`或$(),两者等价

# 3,算数代换:$(())
# 如果一个文件名以 -开头,例如 -help, 则 cmd - help 出错,因为各种UNIX命令都把 -号开头的命令行参数当作命令行选项。可以 cmd . / filename,或 cmd -- filename

# 4,''
# 单引号用于保持引号内所有字符的字面值,即使\和回车也不例外。但是字符串中不能出现单引号。

# 5,""
# 双引号除以下情况保持字符串字面值
#   $ ` \$ \` \" \\
# 
# 交互登录Shell(图形界面的窗口登录器和图形下的终端不是登录Shell)
# /etc/profile  ~/.bashrc ~/.bash_login ~/.profile
#
# 交互非登录Shell(图形界面下的终端,或者登录shell提示符下输入bash得到的Shell)
# ~/.bash_profile 
#
# 非交互启动(Shell脚本)
# 启动时执行的脚本文件由环境变量BASH_ENV定义,相当于执行
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

# 测试命令
# [ -d DIR ] 如果DIR 存在并且是一个目录则为真
# [ -f FILE ]如果FILE 存在且是一个普通文件则为真
# [ -z STRING ] 如果STRING的长度为零则为真
# [ -n STRING ] 如果STRING的长度非零则为真
# [ STRING1 = STRING2 ] 
# [ STRING1 != STRING2 ] 
# ARG1 和ARG2 应该是整数或者取值为整数的变量,OP 是-eq (等于)  -ne (不等于) -lt (小于)  -le (小于等于)  -gt (大于)   -ge (大于等于)之中的一个
# [ ARG1 OP ARG2 ]
 
# 逻辑命令
# [ ! EXPR ] 逻辑反
# [ EXPR1 -a EXPR2 ] 逻辑与
# [ EXPR1 -o EXPR2 ] 逻辑或
#
# 作为一种好的Shell编程习惯,应当总是把变量取值放在双引号之中
# 
# :是一种特殊的命令,称为空命令,Exit STatus总是为真
# Shell中的 && 和 ||具有C语言的Short-circuit特性,注意他和 -a -o的区别
# 例子:
test "$VAR" -gt 1 -a "$VAR" -lt 3
# 等价于
test "$VAR" -gt 1 && test "$VAR" -lt 3
#case 命令可类比C语言的switch/ case 语句,esac 表示case 语句块的结束。C语言的case 只能匹配整型或字符型常量表达式,而Shell脚本的case 可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾必须以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac 之后,不需要像C语言一样用break 跳出。
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!";;
[nN]*)
echo "Good Afternoon!";;
*)
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
exit 1;;
esac
exit 0
#
#
# $0 相当于C语言main 函数的argv[0]
# $1 $2..位置参数, 相当于C语言main 函数的argv[1], argv[2]....
# $@ 参数列表,可用for in遍历
# $$ 当前Shell的进程号

# 和C语言类似,Shell中也有函数的概念,但是函数定义中没有返回值也没有参数列表。例如:
#! /bin/sh
foo(){ echo "Function foo is called";}
echo "-=start=-"
foo
echo "-=end=-"
# 注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号}写在同一行,命令末尾必须有;号。

# Shell提供了一些用于调试脚本的选项,如下所示:
# -n    读一遍脚本中的命令但不执行,用于检查脚本中的语法错误
# -v    一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
# -x    提供跟踪执行信息,将执行的每一条命令和结果依次打印出来

# 正则表达式
#
# 1,字符类
. 匹配任意一个字符
[] 匹配括号中任意一个字符
- 在[]中表示字符范围
^ 位于[]开头,匹配除括号中字符之外的任意一个字符
[[:xxx:]]  grep工具预定义的一些命名字符,如[[:alpha:]]   [[:digit:]]

# 2,数量限定符
? 匹配前面单元零次或一次
+ 一次或多次
* 零次或多次
{N} 精确匹配N次
{N,} 至少匹配N次
{,N} 至多匹配N次

# 3,位置限定符
^ 匹配行首的位置
$ 行末
\< 匹配单词开头
\> 匹配单词结尾
\b 匹配单词开头或结尾
\B 匹配非单词开头或结尾


## sed
/pattern/p 打印匹配pattern的行
/pattern/d 删除匹配
/pattern/s/pattern1/pattern2/
查找符合pattern的行,将该行第一个匹配pattern1的字符串改为pattern2

-n只打印匹配的行
pattern2中的&表示源文件的当前行中与pattern1相匹配的字符串
\1表示与pattern1中第一个()内相匹配的内容

## awk
# 自动变量$1、$2分别表示第一列、第二列等,类似于Shell脚本的位置参数,而$0表示整个当前行。
# awk '$2<75 {printf "%s\t%s\n", $0, "REORDER";} $2>=75 {print $0;}'
# awk '/^ *$/ {x=x+1;} END {print x;}' testfile

#awk 常用内建变量
FILENAME 	当前输入文件的文件名,该变量是只读的
NR 		当前行的行号,该变量是只读的,R代表record
NF 		当前行所拥有的列数,该变量是只读的,F代表field
OFS 		输出格式的列分隔符,缺省是空格
FS 		输入文件的列分融符,缺省是连续的空格和Tab
ORS 		输出格式的行分隔符,缺省是换行符
RS 		输入文件的行分隔符,缺省是换行符