欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux操作系统编程(3)—— shell编程基础

程序员文章站 2022-03-04 19:00:34
...

Linux操作系统编程(3)—— shell编程基础

前两篇文章分别是 常用linux操作命令

常用Linux的命令系统、文件系统和帮助系统

,已经讲述了linux基本命令和文件系统、帮助系统等,因此本文来梳理一下shell编程的语法和样例

变量

在shell中可以直接定义变量并给变量赋值,使用起来感觉类似python

p=1
a=123
#要注意,这里不能有空格,因为添加空格之后就变成一个命令了

如果我们要编写一个脚本的话,就需要先创建一个脚本文件, vim 1.sh 即可

这个脚本的第一行是告诉大家,计算机要用bash解释这个文件,实际上,由于现在的系统比较智能,即便删除了这句话也是可以执行的。

**命令替换符 **

A=`pwd`
#这里的``就是命令替换符,不是单引号,而是键盘左上角,esc下边的那个键
WorkDir=`pwd`
echo -e "ln\033[31;32m${WorkDir}\033[0m"

这里的$是将变量的值取出来,{}起到了确定变量范围的作用,如果是比较简单的命令,不写{}也是可以的。

除了我们自己定义的变量之外,我们编写脚本的时候还要注意有一些特殊的变量、

$0 表示程序自己

$1 表示第一个参数,以此类推,$2 表示第2个参数

$# 得到执行当前脚本的参数个数

$* 获取当前shell的所有参数,将所有命令参数视为单个字符串

[email protected] 也表示所有参数, 但是所有参数是分开的,保留参数之间的空白,可以传参给别的程序

$? 判断上一条指令是否执行成功, 0 表示成功,其他数字表示不成功

$$ 取当前进程的PID

$! 上一个指令的PID

#!/bin/bash
echo "hello, everyone!"
#是注释,第一行是固定格式,说明解释器
WorkDir=`pwd`
echo -e "In\033[31;32m ${WorkDir} \033[0m"
echo "program Name : $0"
echo "arg1: $1"
echo "arg2: $2"
echo "arg3: $3"
echo "arg4: $4"
echo "arg5: $5"
echo "arg6: $6"
echo "\[email protected] : [email protected]"
echo "\$* : $*"
echo "\$# : $#"
ls /etc1
echo "\$? : $?"
last | grep "xxx" 1>/dev/null 2>/dev/null
if [[ $? -eq 0 ]];then
    echo -e "$Name logged In!\n"
fi

参数展开

${parameter:-word} 如果变量未定义,则表达式的值为word

${parameter:=word} 如果变量未定义,则设置变量的值为word,返回表达式的值也是word

${parameter:?word} 用于捕捉由于变量未定义而导致的错误并退出程序

${parameter:+word} 如果变量已经定义,返回word也就是真

${!prefix*}

${[email protected]} prefix 开头的变量

字符串展开

${#parameter} 输出字符串的长度

${parameter:offset} 从第offset开始截取

${parameter:offset:length} 从offset开始截取,取length长度

${parameter#pattern} 从头删除最短匹配

${parameter##pattern} 最长

${parameter%pattern}从尾删除最短

${parameter%%pattern} 从尾删除最长

${parameter/pattern/string}第一个匹配被替换

${parameter//pattern/string} 全部匹配被替换

${parameter/#pattern/string} 字符串开头的替换

${parameter/%pattern/string} 字符串结尾被替换

${parameter,} ${parameter^^} 全部转换为小写、大写

${parameter,} ${parameter^} 首字母转换为小写、大写

分支判断结构

条件判断语句

if [[ contdition ]];then
	#statements
fi
#或
if [[ condition ]];then
	#statements
	else
	#statements
fi

在if 的括号里边,左右必须有空格,中间的条件判断就是test表达式

-n 针对字符串,长度不为0

-z 针对字符串,长度为0

== != 这是常规的用法

对于整型

-eq 等于

-ge 大于等于 greater than or equal

-gt 大于

-le 小于等于

-lt 小于

-ne 不等于

对于文件

-ef 是否是同一个文件

-nt 前一个是不是更新的

-ot 前一个是不是更老的

-b 判断是否存在,且是二进制格式文件

-c 判断是否存在且是字符

-d 判断是否存在且是目录

-e 文件存在

-f 存在且是普通文件

-g 存在且是一个组

-G存在且所属组是有效地

Targetfile='a.c'
if [[ -r ${Targetfile} ]];then
	gcc a.c -o a
	./a
else
	echo "${Targetfile} not found!"
fi

while语句

while [[ condition ]];do
	#statements
done

循环语句

for i in words;do
	#statements
done
#for循环也可以 for i in `seq 1 100` 这个是用系统生成序列
for (( i=0; i<10; i++ ));do
	#statements
done

until [[ condition ]];do
	#statement
done

case word in
	pattern)
		;;
		*)
		;;
esac
read a
case $a in
	1)
		echo 1
		;;
	2)
		echo 2
		;;
	*)
		echo "not found!"
		;;
esac
num=0
while [[ $num -lt 100 ]];do
	echo ${num}
	num=$[ ${num} + 1 ]
done

数组

declare -a a
	name[subsript]=value
		name=(value1 value2...)
		
D=(1 2 3 4 5 6 7)
File=(`ls`)
#输出数组内容如下
${array[*]}
#或
${array[@]}
#确定数组元素的个数
${#array[@]}
#找到数组下标,看看有多少个
${!array[@]}
#数组追加
array+=(a b c)
#数组排序
sort
#删除数组与元素
Unset

基本的流程结构就这些,如何使用下面举几个例子

求偶数和

sum=0
for (( i=1; i<=100; i++));do
	if [[ $[ ${i} % 2 ] -eq 0 ]];then
		sum=$[ ${sum} + ${i} ]
	fi
done
echo "sum = ${sum}"

暴力求素数

#!/bin/bash
#首先定义一个函数,用来输出脚本的用法
function Usage(){
	echo "Usage : $0 start_num end_num"
	exit
}

#暴力判断是不是素数
function is_prime(){
	num=$1
	#num就是传入的参数
	for(( j=2; j<${num}; j++));do
		if[[ $[ ${num} % $j ] -eq 0 ]];then
			return 1
		fi
	done
	return 0
}
#如果调用脚本时参数数量少于两个,就返回Usage
if [[ $# -ne 2 ]];then
	Usage
fi
#分别用脚本的第一个和第二个参数为start和end 赋值,并将sum初始化
Start=$1
End=$2
sum=0
for (( i=${Start}; i<=${End}; i++ ));do
	is_prime $i
	#判断这个数是不是素数,如果上一条命令执行结果是零就加和进去
	if [[ $? -eq 0 ]];then
		sum=$[ ${sum} + $i ]
	fi
done

echo ${sum}

用素数筛法求素数和

if [[ $# -ne 2 ]];then
	echo "error"
	exit
fi
Start=$1
End=$2

declare -a Prime
#定义数组
function init_prime(){
	local end=$1
	#定义了一个局部的变量
	local i
	Prime[1]=1
	for (( i=2; i<=${end}; i++ ));do
		for(( j=$[ ${i} * ${i} ]; j<=${end}; j+=i ));do
			Prime[${j}]=1
			#被标记为1,不是素数
		done
	done
}

init_prime ${End}
sum=0
#下面的命令可以输出数组所有内容
echo ${Prime[*]}

for (( i=${Start}; i<=${End};i++ ));do
	if [[ ${Prime[$i]}x == x ]];then
	#这句话就是判断是不是零,如果是零,拼接上x还是等于x
		sum=$[ ${sum} + $i]
	fi
done
echo ${sum}

在此基础上还有线性筛,主要的改动如下

function init_prime(){
    local end=$1
    local i
    Prime[1]=1
    for (( i=2; i<=${end}; i++ ));do
        if [[ ${Prime[$i]}x == x ]];then
            Prime[0]=$[ ${Prime[0]} + 1 ]
            Prime[${Prime[0]}]=$i
            sum=$[ ${sum} + $i ]
        fi
        for (( j=1; j<=${Prime[0]}; j++ ));do
            if [[ $[ $i * ${Prime[$j]} ] -gt ${End} ]];then
                break;
            fi
            Prime[ $[ $i * ${Prime[$j]} ] ]=1
            if [[ $[ $i % ${Prime[$j]} ] -eq 0 ]];then
                break;
            fi
        done
    done
}