[Note] Linux学习笔记7 shell编程基础

567 查看

Note 7 Linux Shell编程基础

基本概念

shell脚本,一个shell程序,由可执行的shell命令组成,以普通linux文件形式保存
运行一个shell脚本的方法:

  1. chomd u+x scriptfile ./scriptfile

  2. /bin/bash scriptfile

shell变量,shell允许使用一些读写存储区,为用户和程序设计人员提供一个暂存数据的区域,分为环境变量和用户定义变量

环境变量用来定制shell运行环境,保证shell命令正确执行,所有环境变量会传递该shell的子进程
环境变量大多在/etc/profile文件中初始化,而profile是在用户登录时执行的。
用户可以在用户的~/.profile中给部分或全部环境变量赋值,或者在~/.bashrc,~/bash_log,~/.bash_profile中修改,它们在bash启动时执行
我们可以通过echo $变量名 来打印变量,具体的环境变量请自行查阅(set、env、declare、typeset、printecv等命令可以显示环境变量和其值)

用户变量在shell脚本汇总被用于临时的存储空间,一个没有初始化的变量自动被初始化为一个空串,用shell内嵌命令declare、local、set、typeset来初始化用户变量

程序流程控制命令,提供了对shell脚本中命令进行非顺序执行或循环执行的功能

变量相关

bash并不要求你一定声明变量,但是我们可以通过declare和typeset命令来声明变量,对变量初始化,并设定它们的属性,语法:

declare [options] [name[=value]]
typeset [options] [name[=value]]

常用options:

  • -a 每个name是一个数组

  • -f 每个name是一个函数

  • -i name是一个整数

  • -r 给每个name标记上只读属性

  • -x 表示每个name都可以被子进程访问到
    例如:

declare -i age=20
declare -rx os=linux

注意:一个整型变量不能赋予非整型的值,非整型的变量可以被赋予任何值

变量读写
语法:varable=value $varable
例子:

myloc=/usr/test
echo $myloc
ls $myloc

注意:(1)等号前后没有空格 (2)读取变量时前面加‘’$‘’

变量读取--命令替代操作符
以下varable代表变量名,string代表一个字符串

  • $varable 返回变量的值,如果没有初始化则返回null

  • ${varable} 返回变量的值,如果没有初始化则返回null,常用于数组变量

  • ${varable:-string} 若变量存在且非空,返回变量的值,否则返回string的内容

  • ${varable:=string} 若变量存在且非空,返回变量的值,否则把string赋给变量并返回

  • ${varable:?string} 若变量存在且非空,返回变量的值,否则显示字符串‘'varable:'和string

  • ${varable:+string} 若变量存在且非空,返回string的值,否则返回null

例程:

$echo $name     #name is null
                #this is space           
$name=xiaoming  
$echo $name     
xiaoming

$echo ${name:-john} ${place:=varIsNull}
xiaoming varIsNull
$echo ${place:?"not defined."}
bash: place: not defined.
$echo ${name:+defined}
defined
$echo ${place:+"not defined"}
$echo ${place:="hz"}
hz

符号"" '' *的使用
使用双引号将值括起来,则允许使用$符号对变量进行替换,但对大多数的元字符(包括*)都将按字面意思处理
使用单引号将值括起来,则不允许使用变量替换,并不对它进行shell解释
使用反斜杠去除字符的特殊含义,并把它们按字面意思处理,比如$

命令替换
当一个字符串被包含在一堆括号里,并在前面加$符号,或者被包含在反引号 ` 中,则该字符串被作为命令执行,并用命令的执行结果替换这个字符串本身。
语法:$(command) `command`

定义全局变量

declare -x[name-list]
typedef -x[name-list]
export [name-list]

以上命令把name-list中的变量名字和它们的值扩展到之后每一个命令里
例如:

$declare -x name=global

重设变量
unset [name-list]
将name-list中的变量重设为null
例如:

unset name place

注意:不能重设只读变量的值

shell脚本

读入参数

1.从标准输入设备读入变量
read [options] var-list
用途:从标准输入设备读入一行,将读入的词存入var-list变量中,读入的一行输入由多个词组成,中间由空格或tab分隔。如果这些词的数量比列出的变量多,那么将余下的所有词赋值给最后一个变量,反之,设为null

2.直接传递给shell脚本
在运行脚本时,在脚本名之后直接输入参数
例如:$bash scriptfile val1 val2 val3
这些变量的前9个存放在shell变量$1 到 $9中,可以使用shift [N]命令把参数化向左移动N个位置
$#变量包含了传递的参数的个数
$* 和 $@ 都包含了所有参数的值,他们的区别在于,当被引号包括时,$@把每个参数的值作为一个字符串,而不是把所有参数的值作为一个字符串
$0包含了脚本文件的名字

3.set命令
可以使用set命令将值存到位置参数里
例如:

$set $(date)
$echo "$@"
Thu July 20 21:33:09 PST 2016

date命令的输出有6个域,被存到$1到$6之中

程序流程控制语句

推荐一个写的不错的网站
http://www.freeos.com/guides/lsst/
推荐一本书《linux命令行与脚本编程大全》,pdf下载地址
http://pan.baidu.com/s/1slkXFxN

一些shell编程练习及答案:

1.统计指定目录下的普通文件、子目录及可执行文件的数目,以及普通文件字节数总和,目录的路径名字由参数传入

printf "Please input file path\n";
read filepath
i=0;
j=0;
fn=0;
dn=0;
xn=0;
bn=0;
#store filename in an array
for s in `ls $filepath`; do
    files[i]=$s;
    let "i++";
done
#traversal all files
while ([ $j -lt $i ]); do
    ts=$filepath"/"${files[j]};
    #if the file is ordinary file,fn++
    if [ -f $ts ]; then
        let "fn++";
        for ts in `wc -c $ts`; do
            res=$ts;
            break;
        done
        bn=$[$bn + $res];
    #if the file is directory,dn++
    elif [ -d $ts ]; then
        let "dn++";
    fi
    #if the file is executable,xn++
    if [ -x $ts ]; then
        let "xn++";
    fi
    let "j++";
done  
printf "%-10s : %-5d\n" Ordinary File $fn;
printf "%-10s : %-5d\n" Directory $dn;
printf "%-10s : %-5d\n" Executable File $xn;
printf "%-10s : %-5d\n" Total Byte $bn;

2.整数排序及寻找最大最小值

#prodecue random number
random(){
   min=$1;
   max=$2;
   ran=$[ $max - $min ];
   num=`date +%s+%N`;
   return $[ $num % $ran + $min ]; 
}
#store 100 random number into array
for((i=0;i<100;++i)); do
    random 1 10000;
    array[$i]=$?;
    printf "%d " ${array[$i]};
done
printf "\n";

#echo "Please input some integer";
#read -a array;
i=0;
mmin=201607010;
mmax=0;
while([ $i -lt ${#array[@]} ]); do
    if [ $mmin -gt ${array[$i]} ]; then
        mmin=${array[$i]};
    fi
    if [ $mmax -lt ${array[$i]} ]; then
        mmax=${array[$i]};        
    fi
    let "i++";
done
#inset sort algorithm using two for loop
#time complexity is O(n2)
num=${#array[@]};
for((i=1;i<num;++i));do
    tem=${array[$i]};
    for((j=i-1;j>=0;--j));do
        if [  ${array[$j]} -gt $tem ]; then
            array[$[ $j + 1 ]]=${array[$j]};
            array[$j]=$tem;
        fi
    done
done
#output the res:MAX,MIN,SORT
echo "Max: $mmax";
echo "Min: $mmin";
k=0;
echo "Sort:"
while [[ $k -lt $num ]]; do
    printf "%d " ${array[$k]};
    let "k++";
done
printf "\n";

3.输入一个字符串,过滤掉所有非字母字符,然后判断是不是回文字符串

echo PLease input a string:
read str;
#filter other char 
str2=`echo -n $str|tr -d -c 'a-zA-Z'`;    
echo After filter:$str2;
len=`echo -n $str2|wc -c`;                
mid=`expr $len / 2`;                   
l=1;
#judge palindrome
while [ $l -le $mid ]; do
    c1=`echo -n $str2|cut -c $l`;
    c2=`echo -n $str2|cut -c $len`;
    if [ $c1 != $c2 ]; then
        echo "$str2 isn't a palindrome";
        break;
    fi
    l=$(($l+1));
    len=$(($len-1));
done
if [ $c1 = $c2 ];then
    echo "$str2 is a palindrome"
fi