Shell Study Notes
指导思想:
10分钟语法+实操
\ + ENTER 换行
变量
shell变量无需声明即可用,默认空值
于shell,变量常量无区别,用大小写区别
所有变量视为字符串
变量赋值
Here文档
输入到一个命令的标准输入中
cmd << token
text(单双引号视为普通字符)
token
cmd <<- EOF
text(单双引号视为普通字符,忽略Tab字符,可用来缩进)
EOF
函数
function name {
cmds
return
}
name() {
cmds
return
}
局部变量定义
local variable
#!/bin/bash
ANSWER=maybe
if [ -z “$ANSER” ]; then #须有“”防止参数为空导致错误($被解读为非空)
echo “no answer” >&2
exit 1
fi
if [ “$ANSER” = “yes” ];then
echo “answer is yes”
elif [ “$ANSER” = “no” ]
echo “ answer is no”
else
echo “answer is maybe”
fi
exit
退出状态
echo $? 显示上一命令退出状态,0成功,非0失败
echo $! 后台最后一次运行的进程pid
#true/false 系统内置命令,以0/1退出状态终止执行
test命令
test expression 更广泛
[ expression ]
测试命令,表达式为true,退出状态0。false非0;特殊符号< > ( )须引号或 \转义
[ [ expression ] ] 支持REG,bash独有
[ [ str=~regex ] ] string与正则表达式regex匹配为true
[ [ str == foo.* ]] 支持模式匹配*,类似路径名扩展
(()) 整数专用,无须扩展,名字识别变量--(( INT == 0 ))
文件测试
[ -e file ] file 存在为true
[ -f file ] file存在且为普通文件
[ f1 -nt f2 ] f1新于fe为true
字符串测试
[ string ] 非空为true
[ -n str ] str长度>0为true
[ -z str ] 长度=0为true
[ str1 '>' str2 ]
整数测试
[ int1 -lt int2 ] <
[ int1 -le int2 ] <=
[ int1 -ne int2 ] not =
整数regex=^-?[0-9]+$
控制运算符
mkdir tem && cd tem
[ -d dir ] || mkdir dir
[ $(id –u) == 0 ]为root
读取标准输入
echo -n 不换行输出
$echo -n "123"
$echo "456"
最终输出 123456
而不是
123
456
echo -e enable interpretation of backslash escapse使能\转义
read [-option] [var…]
-p str 用字符串str为提示符
-t N N秒超时结束输入
-s 保密模式,屏幕不显示
若var缺省,系统自动分配shell变量REPLY
不可重定向,echo “$str” | read用法错,REPLY在read执行完后赋值丢失(|开启子shell无法继承父shell)
IFS
IFS=“:” read user pw uid <<< “$file_info”
IFS--Internal Field Separator,shell变量,默认space,Tab,Enter
IFS=:赋值只在read执行周期有效
<<<指示嵌入字符串,其后接字符串
P371 核心代码分析:
file_info=$(grep “^$user_name:” $FILE)
IFS=“:” read user pw uid gid name home shell <<< “$file_info”
grep打印匹配【行】故file_info=$(grep...)返回匹配【行】(内容)
$()为命令替换,同``
$user_name,$FILE为参数扩展
^在‘’内保留特殊意义???
IFS赋值只在该行read命令执行周期有效
常见regex
文件名regex: ^[-[:alnum:]\._]+$
整数regex: ^-?[[:digit:]]+$
浮点数regex: ^-?[[:digit:]]*\.[[:digit:]]+$
if结构
if cmds; then
cmds
[elif cmds; then
cmds…]
[else
cmds]
fi
while结构
while cmds;
do
continue;
done
until结构
until cmds;
do
break;
done
for结构
1)
for var [in words];
do
cmds
done
words--
- {A...Z}
- *.txt
- $(string $1)
- 被忽略时var为位置参数
2)
for ((exp1;exp2;exp3));
do
cmds
done
exp为算术表达式,同C语言
case结构
case word in
[pattern [| pattern]…)
;;
a|A)
;;
???)
;;
*)
;;
esac
pattern同路径名扩展: *?[:[alpha]:]
路径名扩展区别Regex???
循环读取文件
文件到达EOF前为true
1)
while read x y z;
do
cmds;
done
2)
sort -k 1,1 k 2n | while read x y z;
do
cmds;
done
调试
echo rm * #TESTING 显示扩展,降风险
#!/bin/bash -x #追踪整个脚本
set -x #追踪部分脚本
…
set +x
#export PS4='$LINENO + '
位置参数变量
$0-$9,${10}...存储命令行关键字
$0 –- 所执行程序path
$#,${#*},${#@}–- 位置参数个数(自动计算命令行参数数目)
shift? 位参自动下移 瓢or指针?
$(basename $0)--截断路径$0,只留文件名
$* –-
扩展为1开始参数列;
“$*” 扩展为 字符串“$1 IFS $2...”
$@ –-
扩展为1开始参数列;
“$@” 扩展为 字符串“$1” “$2”…
参数扩展
可提升效率
${a} 基本参数扩展
${para:-word} para未设,(表达式)取word值
${para:=word} para未设,取word值,并赋值
${para:+word} para未设,取null; or取word值
${para:?err_msg} para未设,打印err_msg到stderr
${!pre*} 返回pre为前缀的变量名
${!pre@} 返回pre为前缀的变量名
${#para} 返回变量para内字符串长度
${para:offset} 提取para变量内字符串,offset位开始,直到末尾
${para:offset:length} 提取字符串,offset位开始,共length位
offset可为负,前须有space,代表字符串末尾开始
${para#pattern} 去除最短匹配;pattern为模式
${para##pattern} 去除最长匹配;pattern为模式
${para%pattern} 去除最短匹配;从字符串尾进行
${para%%pattern} 去除最长匹配;从字符串尾进行
${para/pattern/string} para内容匹配到pattern,则用string替换
${para//pattern/string} para内容匹配到pattern,则用string全局替换
${para/#pattern/string} para内容头匹配到pattern,则用string替换
${para/%pattern/string} para内容尾匹配到pattern,则用string替换
算术扩展$((exp))
if (( i=5 )) i赋值5;赋值成功,返回true
for (( i=0;i<5;++i ))
逻辑操作
((exp1?exp2:exp3)) exp1非0执行exp2;or执行exp3
bc
bc < f.bc
bc f.bc
bc <<< “2+2”
数组
bash仅支持一维数组,元素类型限定为字符串和整数
创建数组ar
declare -a ar
数组赋值
ar[0]=str
color=(red green blue)
color=([0]=red [1]=green [2]=blue)
ar=str str赋给ar[0]--无下标引用默认指ar[0]
单元素访问
${ar[0]} 取ar[0]值
所有元素访问
for i in “${a[@]}”;
do
echo $i
done
确定数组长度(元素个数)
${#a[@]}
查找数组下标
${!a[@]}
${!a[*]}
数组尾自动增加元素
a+=(x y z…)
数组排序
a_sorted=($(for i in “${a[@]}”; do echo $i; done | sort))
删除
unset 'a[0]'
unset ar
组命令
不丢失环境改变,更快,更少内存
{ cmd1; cmd2; [cmd3;…] } >(<,>>,<<)
子shell
丢失环境改变
(cmd1; cmd2; [cmd3;…]) |
进程替换
<(cmdlist)
>(cmdlist)
echo “foo” | read
echo $REPLY
显示空。|管道开启子shell,read执行完后REPLY赋值丢失
read < <(echo “foo”)
echo $REPLY
显示foo。<(echo “foo”)进程替换,将子shell (echo “foo”)输出视为普通文件
while read x y z…; do
cat <<- EOF
Filename: $z
…
EOF
done < <(ls -l | tail -n +2)
进程替换 输出 定向到 循环 标准输入
trap
trap “echo 'i am ignoring you'” SIGINT…
脚本接收到INT(ctrl-c)信号时,trap执行echo命令
wait命令
async-child & #父进程--后台执行子进程)
pid=$! #$!记录后台最后运行进程pid,即子进程)
…
wait $pid #父进程暂停
管道命名
mkfifo pipe # prw-r—r--
更多命令在/usr/bin