目录结构:/d/home/bash_test/
total 39
drwxr-xr-x 1 Administrator 197121 0 12月 6 16:22 demo_folder1/
drwxr-xr-x 1 Administrator 197121 0 12月 6 16:22 demo_folder2/
prw-rw-rw- 1 Administrator 197121 0 12月 10 20:09 my_pipe|
-rwxr-xr-x 1 Administrator 197121 40 12月 15 02:19 pub.sh*
-rw-r--r-- 1 Administrator 197121 1311 12月 15 02:25 t.tmp
-rwxr-xr-x 1 Administrator 197121 12018 12月 15 02:28 ta.sh*
pub.sh的代码:
#!/bin/sh
pub(){
echo "pub_sh_func";
}
ta.sh的代码:
#!/bin/sh
#导入同目录下的pub.sh
#被包含的文件不用设置执行权限
. ./pub.sh
#调用pub.sh中的函数pub
pub;
#下方使用多行注释
<<EOF
######打印重复字符的函数#################
#参数有两个: #
##参数一为指定字符,默认值为" .* "号 #
##参数二为指定重复次数,默认值为80 #
#########################################
EOF
echo_line(){
#定义局部变量以便接参操作
local symbol=$1;
local num=$2;
#######常见默认值判断######
#if [ $# -eq 0 ]
#then
# symbol="=";
# num=80;
#fi
######常见判断结束######
######不正常人的默认值判断方式######
#用${foo:=bar}对foo位置默认值进行判断空后赋值为bar
#symbol=$(echo ${symbol:="="});
#num=$(echo ${num:=80});
######不正常判断结束######
######正常和不正常的公用部分######
#星号*会被解析成文件,要单独处理一下,
#等号两边要求类型相同,变量用引号括上或者判断时用双层括号
#line=$(printf "%-${num}s");
#if [ "*" == "$1" ]
#then
# echo "${line// /*}";
#else
# echo "${line// /${symbol}}";
#fi
######公用部分结束######
######更简略的不正常写法######
#line=$(printf "%-$(echo ${num:=80})s");
#if [ "*" == "$1" ]
#then
# echo "${line// /*}";
#else
# echo "${line// /$(echo ${symbol:="="})}";
#fi
######简略的写法结束######
######其他写法######
if [ $# -eq 0 ]
then
symbol="=";
num=80;
fi
printf "$symbol%-.0s" $(seq 0 $num);
printf "\n";
######其他结束######
}
for_test(){
for file in $(ls -d */)
do
printf "$file ";
done
printf "\n";
}
chapter1(){
echo "chapter1:";
#只读和删除变量,只读无法删除
readonly temp=" ";
unset temp;
echo "echo字符试试\!"
a=10;
b=20;
c=$((a+b));
#expr只有乘法需要转义+ - / % **都直接配合即可,
#注意expr的参数为变量时不要忘记双引号和$号
d=`expr "$a" \* "$b"`;
#调用变量记得用双引号括起来
echo -e "a=10\tb=20\ta和b的和:c = ${c}";
echo -e "a=10\tb=20\ta和b的积:d = ${d}";
test $a -lt $b && { echo "a less than b is true";} || echo "a less than b is false";
echo "数值比较一共六种: eq ne gt ge lt le"
}
chapter2(){
echo "chapter2:";
str="hello";
str_add="_world";
#字符串的合并
str_comb=${str}${str_add};
echo -e "str : ${str}\tstr_add : ${str_add}\tstr_comb : ${str_comb}";
#字符串判空
#特意写了一个否定判断,注意这里布尔值取反的方法
#另外还运用了一下&&的短路写法,||也一样
!(test -z ${str_comb}) && echo "test -z \$str_comb为假, str_comb不空";
test -n ${str_comb} && echo "test -n \$str_comb为真, str_comb不空";
#字符串的长度
echo "str_comb的长度为: ${#str_comb}";
#字符串比较
echo_line;
#查找字符的操作
#查找字母w或者o,返回的索引从数字1开始
index_num=`expr index "${str_comb}" wo`;
cur=$((${index_num}+1));
echo "在变量str_comb中查找字母w或o返回的索引: ${index_num},对应下标为: ${cur}";
#取字符
#取指定位置字符,
#第一个冒号后是字符串的下标,从0开始
#第二哥冒号后是包含指定下标的字符在内一共要取的字符的个数
recv_str="${str_comb:${cur}:1}";
echo "查找到的字符为: ${recv_str}";
echo "在str_comb中从指定下标6开始取字符到末尾得到: ${str_comb:6}";
#替换字符
#替换第一个匹配的字符
str_comb=$(echo ${str_comb/"world"/"bash"});
echo "替换str_comb中的\"world\"为\"bash\": ${str_comb/"world"/"bash"}";
echo_line;
echo "str_arr 的三个成员str、str_add、str_comb:";
#set -v on;
str_arr=(
"${str}"
"${str_add}"
"${str_comb}"
);
echo "${str_arr[@]}";
#for mem in $(seq 0 2)
#do
# echo ${str_arr[$mem]};
#done
#set +v;
str_arr_comb=$(echo ${str_arr[@]});
echo "拼接数组元素为str_arr_comb: ${str_arr_comb}";
echo "替换str_arr_comb中所有的\"hello\"为\"hola\": ${str_arr_comb//hello/hola}";
echo_line;
length=${#str_arr[@]};
echo "数组str_arr的长度为: ${length}";
}
chapter3(){
echo "chapter3";
echo "变量的判断: ";
echo "\":-\"";
echo "注:以下提到的null均代表未赋值或不存在";
echo "注:shell真值和假值的否定均为真";
local b=1;
echo "a赋值为null,b赋值为1,\${a:-\$b}返回值为: $(echo ${a:-$b})";
local a=1024;
echo "a赋值为1024,b赋值为1,\${a:-\$b}返回值为: $(echo ${a:-$b})";
unset a;
echo "a赋值为null,b赋值为1,\${a-\$b}返回值为: $(echo ${a-$b})";
local a=1024;
echo "a赋值为1024,b赋值为1,\${a-\$b}返回值为: $(echo ${a-$b})";
unset a;
echo -e "以上两种判断总结: \n\ta为真返回a,\n\ta为假返回任意指定值b,
有点像C语言的\" ?: \",不同的是此处真值返回值为判断值本身\n";
echo "a赋值为null,b赋值为1,\${a:+\$b}返回值为: $(echo ${a:+$b})";
local a=1024;
echo "a赋值为1024,b赋值为1,\${a:+\$b}返回值为: $(echo ${a:+$b})";
unset a;
echo -e "\":+\"判断总结:\n\ta为真返回值为任意指定值b,返回值的否定依然为真,
a为假返回值为null,返回值否定为真,\n\t适合做变量关联或返回值绑定,
即对a判真后返回值为b,对a判假返回值为假,与\" := \"判定结果相反,";
echo -e "\t应用举例见代码: ";
set -x;
local word=1;
if test $(echo ${var:+$word}) ;then
echo -e "执行结果打印:$var\n";
fi
local var=1024;
if test $(echo ${var:+$word}) ;then
echo -e "执行结果打印$var\n";
fi
set +x;
echo "a赋值为null,b赋值为1,\${a:=\$b}返回值为: $(echo ${a:=$b})";
local a=1024;
echo "a赋值为1024,b赋值为1,\${a:=\$b}返回值为: $(echo ${a:=$b})";
unset a;
echo -e "\":=\"判断总结:\n\ta为真返回a,\n\ta为假赋值b给a并返回,
只有这个判定对变量a做出了赋值操作,
适合用于默认值赋值操作,
即a真返回a,a假返回赋值为b的a,用\$()和echo捕捉结果赋值回a";
}
chapter4(){
echo "chapter4";
echo "文件测试:";
pth="/d/home/bash_test";
echo "pth目录: $pth";
test -d $pth && echo "test -d \$pth目录存在";
echo "pth目录下文件$(ls -al ${pth})";
echo_line;
fl="$pth/ta.sh";
echo "fl文件: $fl";
test -e $fl && echo "test -e \$fl, fl文件存在";
test -s $fl && echo "test -s \$fl, fl不为空";
test -r $fl && echo "test -r \$fl, fl可读";
test -w $fl && echo "test -w \$fl, fl可写";
test -x $fl && echo "test -x \$fl, fl可执行";
test -b $fl || echo "test -b \$fl, fl不是块设备文件";
test -c $fl || echo "test -c \$fl, fl不是字符设备文件";
test -f $fi && echo "test -f \$fl, fl是普通文件";
test -u $fl || echo "test -u \$fl, fl的user执行位(SET USER ID)未被设置成s
执行者无法以文件所有者身份执行文件";
(test -g $pth -o -g $fl) ||
echo "test -g \$pth和\$fl, pth和fl的group执行位(SET GROUP ID)均未被设置成s
执行者无法以文件所有者群组身份执行文件";
test -k $pth || echo "test -k \$pth, pth的other执行位未设置成防删除位(stick bit)t";
echo_line;
pp="$pth/my_pipe";
echo "pp文件: $pp";
test -p $pp && echo "test -p \$pp, pp是有名管道";
echo_line;
echo "创建一个软链接";
test -e $pth/tb.sh || touch $pth/tb.sh;
#脚本之前执行过,删除一下软链接文件
#windows不支持链接类型l,所以用选项 -e
test -e $pth/tbb && rm $pth/tbb;
set -v on;
ln -s $pth/tb.sh $pth/tbb;
#此处同上,windows创建出的文件属性不是链接文件l,而是普通文件-
set +v;
#注意这里的 :&&{ :;}||: 三目运算,左大括号后的空格和右大括号前的分号是必须,冒号是占位符
ls -Al $pth/tbb;
test -L $pth/tbb && { echo "test -L $pth/tbb: exist";} || echo "test -L $pth/tbb: not exist";
test -e $pth/tbb && { echo "test -e $pth/tbb: exist";} || echo "test -e $pth/tbb: not exist";
#删除源文件产生tb.sh产生无效链接tbb
rm ./tb.sh;
#一条命令删除指定目录无效链接文件,其他参数操作请查看手册
find ./ -xtype l -delete;
echo "
#提一嘴grep的正则
#fgrep是不用正则
#grep是正常正则只认以下几个元字符 ^ $ . [ ] *
#egrep是grep元字符基础增加了 ? + | 和 ( ) { }
#并且egrep中 ( ) { } 四个符号均需要转义使用";
}
chapter5(){
#printf后方跟的参数间的空格是必须
printf "chapter5\n";
echo "printf函数";
printf "%-10s %-8s %-4s %4s\n" "姓名" "性别" "体重kg" "成绩";
printf "%-10s %-8s %-4.2f %4c\n" "郭靖" "男" 66.1234 "C";
printf "%-10s %-8s %-4.2f %4c\n" "杨过" "男" 48.6543 "A";
printf "%-10s %-8s %-4.2f %4c\n" "郭芙" "女" 47.9876 "B";
}
chapter6(){
echo "chapter6";
echo "标准输入输出重定向";
echo "将head \$0命令结果发送到发送到标准输出1:";
#标准输出的1是默认开启,所以一般不写
head -5 < $0 1;
test -e ./t.tmp || touch ./t.tmp;
#把/dev/null这个无底洞通过标准输出定向到文件,达到清空文件的效果
/dev/null 1> ./t.tmp;
#如上使用过stdout定向后,stderr可以定向到stdout
ls -al ./ > ./t.tmp 2>&1;
#从文件读取,追加输出到文件
head -5 < $0 >>./t.tmp;
#here document
printf "here document内行数统计:";
wc -l << EOF
echo "this is a test";
echo "the second line";
#结尾处的EOF旁不能又多余字符,而且必须在行首
EOF
cat << EOF
echo "this is a test";
echo "the second line";
#结尾处的EOF旁不能有多余字符,而且必须在行首
EOF
}
chapter7(){
echo "chapter7";
echo "流程控制:";
if [[ ! 0 ]];then
#0本身也是true,!取反后为false,所以执行结果为false
echo "true";
else
echo "false";
fi
echo -n "请输入一个数字: ";
#用read从控制台读取输入存入变量
read num;
local i=$(($num - 6));
while :
#冒号前的空格很重要,这种写法相当于C语言的while(1)
#其他写法for((;;))或while(true)
do
echo $i;
let i++;
if [[ $i -gt 3 ]];then break;fi
done
while(($i<=$num));do
echo $i;
let "i++";
done
echo "请在下列选项中做出选择:";
choices=( "1" "2" );
select val in "${choices[@]}";do
#输入错误时发送到错误输出stderr即&2中,并执行continue
[[ -n $val ]] || { echo "Invalid choice.">&2; continue; }
echo -n "输入结果(1/2): "
#read val;
case $val in
1) echo "你选择了1";
;;
2) echo "你选择了2";
;;
esac
break;
done
echo "Please input a command(cpu|mem|device|CD-ROM)"
read cmd
case $cmd in
cpu) echo "The cpu information is"
cat /proc/cpuinfo;;
mem) echo "The mem information is"
cat /proc/meminfo;;
device) echo "The device information is"
cat /proc/scsi/device_info;;
CD-ROM) echo "The CD-ROM information is"
cat /proc/sys/dev/cdrom/info;;
*) echo "Your input command is invalid"
esac
#关于循环的一点思考
#i如果想初始化就不能用local修饰,不然while访问不到
i=1;
while((i<=9))
do
printf "i:%d\t" "$i";
for ((j=0;j<$i;j++))
do
#printf后方跟的参数间的空格是必须
printf "j:%d\t" "$j";
if [[ $j -ge 3 ]]; then
#break只终止当前层循环
break;
fi
done
printf "\n";
let i++;
done
}
last_cmd_status_code(){
set -x;
status_code=${?};
echo "status_code:$status_code";
#我们再观察一下if判断语句中status_code的变化
if test ${?} -eq ${status_code}
then
echo "if判断的status_code(在判真分支中为0,在判假分支中为非0): ${?}";
else
echo "if判断的status_code(在判真分支中为0,在判假分支中为非0): ${?}";
fi
set +x;
}
chapter8(){
echo "chapter8";
echo_line;
echo "main的参数个数为: $#";
echo "main的参数(以字符串显示): $*";
echo "main的参数(以字符数组显示): $@";
echo "当前脚本的进程ID: ${$}";
echo "后台最后一个进程的ID: ${!}";
echo "shell当前使用的选项: ${-}";
echo "$(date)";
last_cmd_status_code;
}
main(){
for_test;
for ((i=1;i<=7;i++))
do
echo_line;echo_line;
chapter${i} "$@";
done
}
main "$@";
打印结果:
λ ./ta.sh
pub_sh_func
demo_folder1/ demo_folder2/
=================================================================================
=================================================================================
chapter1:
./ta.sh: line 77: unset: temp: cannot unset: readonly variable
echo字符试试\!
a=10 b=20 a和b的和:c = 30
a=10 b=20 a和b的积:d = 200
a less than b is true
数值比较一共六种: eq ne gt ge lt le
=================================================================================
=================================================================================
chapter2:
str : hello str_add : _world str_comb : hello_world
test -z $str_comb为假, str_comb不空
test -n $str_comb为真, str_comb不空
str_comb的长度为: 11
=================================================================================
在变量str_comb中查找字母w或o返回的索引: 5,对应下标为: 6
查找到的字符为: w
在str_comb中从指定下标6开始取字符到末尾得到: world
替换str_comb中的"world"为"bash": hello_bash
=================================================================================
str_arr 的三个成员str、str_add、str_comb:
hello _world hello_bash
拼接数组元素为str_arr_comb: hello _world hello_bash
替换str_arr_comb中所有的"hello"为"hola": hola _world hola_bash
=================================================================================
数组str_arr的长度为: 3
=================================================================================
=================================================================================
chapter3
变量的判断:
":-"
注:以下提到的null均代表未赋值或不存在
注:shell真值和假值的否定均为真
a赋值为null,b赋值为1,${a:-$b}返回值为: 10
a赋值为1024,b赋值为1,${a:-$b}返回值为: 1024
a赋值为null,b赋值为1,${a-$b}返回值为: 1
a赋值为1024,b赋值为1,${a-$b}返回值为: 1024
以上两种判断总结:
a为真返回a,
a为假返回任意指定值b,
有点像C语言的" ?: ",不同的是此处真值返回值为判断值本身a赋值为null,b赋值为1,${a:+$b}返回值为:
a赋值为1024,b赋值为1,${a:+$b}返回值为: 1
":+"判断总结:
a为真返回值为任意指定值b,返回值的否定依然为真,
a为假返回值为null,返回值否定为真,
适合做变量关联或返回值绑定,
即对a判真后返回值为b,对a判假返回值为假,与" := "判定结果相反,
应用举例见代码:
+ local word=1
++ echo
+ test
+ local var=1024
++ echo 1
+ test 1
+ echo -e '执行结果打印1024\n'
执行结果打印1024+ set +x
a赋值为null,b赋值为1,${a:=$b}返回值为: 1
a赋值为1024,b赋值为1,${a:=$b}返回值为: 1024
":="判断总结:
a为真返回a,
a为假赋值b给a并返回,
只有这个判定对变量a做出了赋值操作,
适合用于默认值赋值操作,
即a真返回a,a假返回赋值为b的a,用$()和echo捕捉结果赋值回a
=================================================================================
=================================================================================
chapter4
文件测试:
pth目录: /d/home/bash_test
test -d $pth目录存在
pth目录下文件total 42
drwxr-xr-x 1 Administrator 197121 0 12月 15 02:45 .
drwxr-xr-x 1 Administrator 197121 0 12月 15 02:45 ..
-rw-r--r-- 1 Administrator 197121 12288 12月 8 14:57 .test.c.swp
drwxr-xr-x 1 Administrator 197121 0 12月 6 16:22 demo_folder1
drwxr-xr-x 1 Administrator 197121 0 12月 6 16:22 demo_folder2
prw-rw-rw- 1 Administrator 197121 0 12月 10 20:09 my_pipe
-rwxr-xr-x 1 Administrator 197121 40 12月 15 02:19 pub.sh
-rw-r--r-- 1 Administrator 197121 756 12月 15 02:45 t.tmp
-rwxr-xr-x 1 Administrator 197121 12018 12月 15 02:28 ta.sh
-rw-r--r-- 1 Administrator 197121 0 12月 15 02:45 tbb
=================================================================================
fl文件: /d/home/bash_test/ta.sh
test -e $fl, fl文件存在
test -s $fl, fl不为空
test -r $fl, fl可读
test -w $fl, fl可写
test -x $fl, fl可执行
test -b $fl, fl不是块设备文件
test -c $fl, fl不是字符设备文件
test -f $fl, fl是普通文件
test -u $fl, fl的user执行位(SET USER ID)未被设置成s
执行者无法以文件所有者身份执行文件
test -g $pth和$fl, pth和fl的group执行位(SET GROUP ID)均未被设置成s
执行者无法以文件所有者群组身份执行文件
test -k $pth, pth的other执行位未设置成防删除位(stick bit)t
=================================================================================
pp文件: /d/home/bash_test/my_pipe
test -p $pp, pp是有名管道
=================================================================================
创建一个软链接
-rw-r--r-- 1 Administrator 197121 0 12月 15 02:46 /d/home/bash_test/tbb
test -L /d/home/bash_test/tbb: not exist
test -e /d/home/bash_test/tbb: exist#提一嘴grep的正则
#fgrep是不用正则
#grep是正常正则只认以下几个元字符 ^ $ . [ ] *
#egrep是grep元字符基础增加了 ? + | 和 ( ) { }
#并且egrep中 ( ) { } 四个符号均需要转义使用
=================================================================================
=================================================================================
chapter5
printf函数
姓名 性别 体重kg 成绩
郭靖 男 66.12 C
杨过 男 48.65 A
郭芙 女 47.99 B
=================================================================================
=================================================================================
chapter6
标准输入输出重定向
将head $0命令结果发送到发送到标准输出1:
head: cannot open '1' for reading: No such file or directory
here document内行数统计:3
echo "this is a test";
echo "the second line";
#结尾处的EOF旁不能又多余字符,而且必须在行首
=================================================================================
=================================================================================
chapter7
流程控制:
false
请输入一个数字: 8
2
3
4
5
6
7
8
请在下列选项中做出选择:
1) 1
2) 2
#? 2
输入结果(1/2): 你选择了2
Please input a command(cpu|mem|device|CD-ROM)
mem
The mem information is
MemTotal: 12547000 kB
MemFree: 8093712 kB
HighTotal: 0 kB
HighFree: 0 kB
LowTotal: 12547000 kB
LowFree: 8093712 kB
SwapTotal: 786432 kB
SwapFree: 648064 kB
i:1 j:0
i:2 j:0 j:1
i:3 j:0 j:1 j:2
i:4 j:0 j:1 j:2 j:3
i:5 j:0 j:1 j:2 j:3
i:6 j:0 j:1 j:2 j:3
i:7 j:0 j:1 j:2 j:3
i:8 j:0 j:1 j:2 j:3
i:9 j:0 j:1 j:2 j:3