shell脚本学习笔记

目录结构:/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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值