Linux Shell编程基础知识

1 篇文章 0 订阅

笔记搬家:

Shell的基本工作原理

一个例子:

# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

# Shell从哪里找到命令,就把该位置赋值给PATH变量
PATH="$PATH:/usr/X11R6/bin"
# 规定光标的基本显示形式。光标将以以下的形式在Shell窗口出现:用户名(\u)、@符号、主机名(\W)及$符号
PS1="[\u@\h\W]\\$ "

#ulimit命令(Shell内置命令)限制核心文件的最大容量为1 000 000 字节。核心文件是破坏了的程序文件的转存,而且占用相当大的磁盘空间
ulimit -c 1000000

#假如用户所属的组名和用户名一致,同时用户id号不大于14
if [ 'id -gn' = 'id -un' -a 'id -u' -gt 14 ]; then
	# 设置umask 为002。若创建的是目录则得到775 的权限,而文件得到664 的权限。否则,umask
	# 被设为022,此时则给予目录755的权限,或给文件644的权限。
	umask 002
else
	umask 022
fi

# 把用户名赋给USER变量(id - un)
USER='id -un'
# LOGNAME变量被赋予$USER的值
LOGNAME=$USER
#将到收件箱(储存新邮件)的路径赋给MAIL变量
MALL="var/spool/mail/$USER"

HOSTNAME='/bin/hostname'
HISTSIZE=1000
HISTFILESIZE=1000
export PATH PS1 HOSTNAME HISTSIZE HISTCONTROL USER LOGNAME MAIL 

# 对于在/etc/profile.d 目录里的所有.sh文件……(见14)
# 14 检查是否为可执行文件,如果是……(见15)。
# 15 用点命令来执行命令。在/etc/profile.d 目录里的lang.sh 和mc.sh 文件分别设置Linux 	
# 的字体和字型,同时还创建一个名为mc的函数,可以用来激活一个名为Midnight Commander 的浏览文件管理程序。
# 16 done关键字标志for循环的结束。
for i in /etc/profile.d/*.sh ; do
    if [ -x "$i" ]; then
       . $i
    fi
done

unset i

变量

变量类型。有两种类型的变量:局部变量和环境变量。局部变量仅在创建它的Shell 中有效,环境变量则对所有创建它的Shell

局部变量和范围

变量的范围是指变量在一个程序中的什么地方是可见的。对于Shell 而言,局部变量的范围限于创建变量的Shell

当给一个变量赋值的时候,不要在等号两边留下空格。如果要将一个变量设置为空,在等号后面跟一个换行符即可。

变量前面的美元符号用于提取其存储的值。

环境变量

环境变量是能为创建它的Shell 及其派生子进程所用的变量,它们也经常被称为全局变量以区分于局部变量。

一般约定环境变量为大写,它们是那些可以通过内置命令export导出的变量。

设置环境变量

要设置环境变量,必须在给变量赋值或设置了变量后使用export命令。

例子 

例子 

例子 

例子 

 

 

 

 

#!/bin/bash
if [[ "${1##*}" = "tar" ]]; then
      echo "tar file"
else
   echo "no tar file"   
fi

位置参量

通常情况下,特定的内建变量,被称为位置参量,它们被用于从命令行向脚本传递参数,或者在函数中用于保存传递给函数的参数。这些变量被称作位置参量是因为它们以数字123……区分,这些数字与它们在参量清单中的位置有对应关系。

Shell脚本的名字保存在变量$0 中,位置参量可以被set 命令设置、重置和清空。

这里的file就是位置参数

数学扩展

Shell 通过运算数学表达式和替换结果来进行数学扩展。在没有双引号和表达式嵌套的情况下,表达式可以被直接处理。

有两种计算数学表达式的格式。

数组

bash 2.x 版本提供了创建一维数组的能力。数组允许你把一串数字、一串名字或者一串文件放在一个变量中。数组的尺寸没有限制,脚标也不必须

是一定顺序的数字。获取数组中某个元素的语法是${arrayname[index]}

判断语句

条件判断语句是几乎所有编程语言中都有的语句,shell中有两种条件判断语句:

if表达式

case表达式

例子 

 

例子 

shell入门的拦路虎:syntax error: unexpected end of file

开始学习bash,每次测试代码都在windows下写好,然后传到linux上执行。

在学习到if 等流程控制的语法的时候,我遇见了第一个难题写的 if 的测试总是不正确:“ if.sh: line 11: syntax error: unexpected end of file ”

----------------------------------------------------------------------------

这个问题解决方案如下:学shell还是用vivim

----------------------------------------------------------------------------

dos文件转换成 unix 文件格式
     dos 格式 文件 传输到 unix 系统时 , 会在每行的结尾多一个 ^M , 当然也有可能看不到 , 但是在 vi 的时候 , 会在下面显示此文件的格式 , 比如   "dos.txt" [dos] 120L, 2532C 字样 , 表示是一个 [dos] 格式文件 , 如果是 MAC 系统的 , 会显示 [MAC] , 因为文件格式的原因有时会导致我们的 unix 程序 , 或者 shell 程序出现错误 , 那么需要把这些 dos 文件格式转换成 unix 格式 , 方法是
     
vi   dos.txt         
     :set 
fileformat=unix
     :w                       

这样文件就转换成 unix 格式 文件了 ,一般在 windows 机器上编写好了文件传到 unix 下就可能会出现这样的情况 , 而一般我们使用 ftp 命令, 常常会加上 bin 参数表示二进制传输, 可是试一下不加 bin 参数 , 可能传到 unix 下就是 unix 格式

#!/bin/bash
if [[ $# -ne 1 ]]; then
    echo "usage: $0 filename"
    exit 1 
fi

cp $1 ./temp.txt > /dev/null 2>&1

if [ $? -eq 0 ]; then
      echo "copy done"
else
      echo "copy error"
      exit 2
fi

echo "i found it" >> ./temp.txt
echo "add finished"
exit 0

Linux Shell >/dev/null 2>&1解释

shell中可能经常能看到:>/dev/null 2>&1

命令的结果可以通过%>的形式来定义输出

分解这个组合:“>/dev/null 2>&1” 为五部分。

1> 代表重定向到哪里,例如:echo “123″ > /home/123.txt

2/dev/null 代表空设备文件

32> 表示stderr标准错误

4& 表示等同于的意思,2>&1,表示2的输出重定向等同于1

51 表示stdout标准输出,系统默认值是1,所以”>/dev/null”等同于 “1>/dev/null”

因此,>/dev/null 2>&1也可以写成“1> /dev/null 2> &1”

那么本文标题的语句执行过程为:

1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,说白了就是不显示任何信息。

2>&1 :接着,标准错误输出重定向 到 标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

if结构应用示例

使用ifthenelse结构编写一个判断命令行所传入参数大小的程序

将所输入数值存放在位置参数$1

$1>100,则输出:the number is greater than 100

$1<10,则输出: the number is smaller than 10

否则输出: the number is between  10 and 100

#!/bin/bash
if [ "$1" -gt 100 ]
then
      echo "the number is greater than 100."
elif [ "$1" -lt 10 ]
then
      echo "the number is smaller than 10."
else
      echo "the number is between 10 and 100."
fi

执行   chmod  +x  ifdemo

           ./ifdemo  100        输入数据测试程序功能

循环

shell中提供了可供灵活处理循环的语句,这些循环可以重复执行一组命令,既可以是事先指定的次数,也可以是直到某种条件满足为止。shell中有三个内部循环命令:

for

while{}

until

例子

例子

 

#!/bin/bash
for file in /etc/*; do
      if [[ "${file}" == "/etc/resolv.conf" ]]; then
            countNameServers=$(grep -c nameserver /etc/resolv.conf)
            echo "Total ${countNameServers} nameserver definde in ${file}"
            break
      fi
done

#!/bin/bash
FILES="$@"
for f in $FILES; do
      # if .bak backup file exits, read next file
      if [[ -f ${f}.bak ]]; then
           echo "Shiping $f file"
            continue
      fi
      /bin/cp $f $f.bak
done

其实,在学习这个for循环中,操作语句部分并没有多少的难度。因为这里就是一些unix操作系统的基本语句所构成的。

而其难点就是在于循环列表的确定。因为这个循环列表关系到for循环运行的两个关键参数,一是循环的次数,二是循环内部操作所需要用到的参数值。也就是说,系统工程师只要精通这个循环列表的编写,那么其他内容不会有问题。

如何编制循环列表?

1、 利用文件来作为循环列表。

 如现在系统工程师需要查找在用户目录下,是否有用户想要的20个文件。这20个文件名字没有什么规律。正常情况下,用户需要一一输入文件名。文件名输入一个,然后查询一次。一共做二十次,显然这操作起来的工作量会非常的大。如果这个文件的数目再增加的话,那么操作起来就会更加的麻烦。

for循环中可以解决这个问题。即只需要在循环列表中将这20个文件名字输入进去,然后再操作语句中通过查询操作在指定目录中查找看是否有相关的文件。若有的话,将位置等信息保存到一个文件中。这就可以简化用户的操作,只需要进行一个for循环即可。同时还可以大幅度的缩短查询的时间。

 但是,此时遇到的一个问题就是要在for循环的循环列表中输入20个文件名字。为此系统工程师希望能够将这些文件的名字保存在文件中,然后让for循环从文件中读取这些内容。这即方便,而且也利于后续的调整。其实在for循环中,是支持从文件中读取相关的列表信息。

  大家都知道,这个cat命令的用途主要是从一个文件中读取相关的信息。如果用过管道符的系统工程师,一定知道,可以将某个命令的结果作为另外一个命令的参数。其实,在这里用到的也是这个原理,只是不需要通过管道符来实现而已。具体来说,这个循环列表可以如下定义。

For name in ‘cat filename.txt’(注意,由于其读取后变为了文本的内容,为此需要加上单引号)

2、 利用系统变量作为循环列表。

  在Unix操作系统中,for循环最大的特色,莫过于可以利用系统变量来作为循环列表。如还是以查询操作为例,用户可能需要从指定的几个文件夹中查找某个文件。而这几个目录都是有环境变量所确定的。如一个系统工程师刚到企业,接替老的系统工程师的工作。此时这位系统工程师就需要知道Unix服务器系统的一些基本配置。而这其中有一项重要的内容就是一些重要环境变量的设置。

 如安装了Oracle数据库,就需要知道其安装路径。若安装了Mail服务器,则需要知道其邮件的存储位置与备份位置等等。如果一一去查看这些环境变量,工作量会比较大。如果换成是笔者的话,不会做这么没有效率的事情。笔者的做法是,编写一个for循环,然后将这些重要的环境变量输出到一个文件中进行备份。这将为笔者后续的工作带来很大的方便。如现在笔者想知道Oracle的安装目录与mail的环境变量,就可以利用下面这个循环列表来实现。

•  For varhome in $ORACLE_HOME $MAIL

3、 利用通配符作为循环列表。

  有时候可能系统管理员有这个要求。在某个文件下有多以txt为扩展名的文件。现在系统工程师可能想一一统计这些文件的大小、创建日期、更新日期等等信息,然后将这些统计信息保存到一个文件中。或者想对这些文件进行改名,如在原先的名字之前加上一个backup的字符串,表示这些文件是备份文件。此时,如果一一对这些文件操作的话,会比较麻烦。那么比较合理的做法就是通过for循环来一次性完成这些任务。

 此时,如何书写这个循环列表呢?笔者认为比较合理、比较简便的方法就是通过通配符来实现。如可以利用如下语句来实现:for filename in *.txt。利用这个循环列表,系统就会从目录中查找所有以.txt为扩展名的文件,然后将其为参数,进行后续的操作。如用户需要进行文件更名的话,则可以使用sed操作来对文件进行重命名。在使用通配符作为循环列表中的参数时,最好采用合适的通配符。因为通配符*或者%其含义不尽相同。

例子:把某个目录下的文件扩展名改为bat,再以时间为文件名压缩打包存放到某个目录

#!/bin/bash
for file in $(ls $1); do
      newFile=${file%.*}.bat
      mv ./$1/$file ./$1/$newFile
      tmp=$(date)
      tar -cvf ./$tmp.tar ./$1
done

例子:从网上下载一个文件,保存到指定目录
 

#!/bin/bash
url=http://rs1.bn.163.com/ent/2009/05/20_canquedege.wma
dir=~/download
wget -P $dir $url 

例子:

设计一个Shell程序,在/userdata目录下建立50个目录,即user1user50,并设置每个目录的权限,其
中其他用户的权限为:读;文件所有者的权限为:读、写、执行;文件所有者所在组的权限为:读、执行

#!/bin/bash
for (( i=1;i<=50;i++ ))
do
      mkdir -p /usrdata/user$i
      cd /usrdata
      chmod 754 user$i
done

一个排序例子:

#!/bin/bash 
values=(39 5 36 12 9 3 2 30 4 18 22 1 28 25)
# 获取长度
numvalues=${#values[@]}
for (( i=0; i < numvalues; i++ )); do
  lowest=$i
  for (( j=i+1; j < numvalues; j++ )); do
      if [[ ${values[j]} -le ${values[$lowest]} ]]; then
          lowest=$j
      fi
  done
  temp=${values[i]}
  values[i]=${values[lowest]}
  values[lowest]=$temp
done
for (( i=0; i < numvalues; i++ )); do
  echo -ne "${values[$i]}\t"
done
echo -e "\n\n-------end---------\n"

  ********************************* 不积跬步无以至千里,不积小流无以成江海 *********************************

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值