Chinaunix首页 | 论坛 | 博客
  • 博客访问: 327915
  • 博文数量: 130
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 554
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-19 19:24
文章分类

全部博文(130)

文章存档

2016年(31)

2015年(16)

2014年(13)

2013年(70)

分类: LINUX

2013-09-12 04:33:19

原文地址:Linux 程序设计之shell 作者:forgaoqiang

1、其他的操作系统中,命令行界面只是图形界面的一个补充,但是在Linux上却非如此,shell可以快速的简单的完成编程和系统管理任务,UNIX构架非常依赖于代码的高度可用性。

2、Shell是一个作为用户与Linux系统间接口的程序,它允许用户向操作系统输入需要执行的命令,甚至可以使用 $(..)语法获取子进程的输出,一般系统自带的只有 bash 和 csh 两种。Linux系统中,总是作为 /bin/sh 安装标准shell是GNU工具集中的bash(GNU bourne-Again Shell),是一个优秀的shell。【大爷的,被坑了,Ubuntu默认的居然是dash】
DASH is a POSIX-compliant implementation of /bin/sh that aims to be as small as possible. It does this without sacrificing speed where possible. In fact, it is significantly faster than bash (the GNU Bourne-Again SHell) for most tasks. 
sh(Bourne):源于UNIX早起版本的最初的shell,Openwrt的默认shell
csh、tcsh、zsh:Cshell及其变体
bash(Bourne Again Shell):免费高可移植性

3、管道和重定向
文件描述符 0代表标准输入,1代表标准输出,2 代表标准错误输出,可以单独定义,默认文件会发生覆盖,如果要阻止覆盖行为,可以使用 set -o noclobber 进行设置,如果需要都定向可以使用 >& 操作符 
kill -HUP 1234 > killout.txt 2>&1

set -o noexec 不执行而是仅仅进行语法检查 set -x
set -o verbose 执行命令之前回显命令
set -o xtrace 处理完命令后再回显
set -o nounset 遇到未定义的变量进行警告提示
set +o 对应的选项,取消这些设定

4、管道
管道符 | 可以用来连接进程,Linux和MS-DOS不同,在Linux下通过管道连接的进程可以同时运行,并且随着数据流在它们之间传递参数,而且是自动协商完成,比如下面的命令:
ps -xo comm | sort | uniq | grep -v sh | more
大体意思是,ps只显示进程名,然后进行排序,然后去掉重复的行,然后取到不叫sh的名字(-v是取反),最后进行分页显示。

shell提供了通配符,支持通配符扩展(Globbing)
* 可以匹配任意的字符串
[set] 取得set集总的任意一个单字符
[^set] 取得非set集合中的字符


more `grep -l POSIX *`  #其中参数 -l 是只输出符合条件的文件名,-L则是输出不符合的
more `grep -l POSIX ./ -r` 这样是等价的
more $(grep -l POSIX *)  比较喜欢这种方式
grep -l POSIX * | more 通过管道

创建脚本

点击(此处)折叠或打开

  1. #!/bin/sh
  2.  
  3. for file in *
  4. do
  5.     if grep -q POSIX $file #参数q代表了quiet模式,不输出
  6.     then
  7.         echo $file
  8.     fi
  9. done
  10.  
  11. exit 0 #退出代码,其中0代表正常退出


!!!! 执行程序的时候一定要小心,特别是root用户,很有可能运行了某个标准命令的伪装版本,建议使用 which 命令检查当前运行命令的实际路径和情况,以确定是否是真正的运行了需要的命令,当然到对应的管理工具当前目录下运行最可靠了。

5、shell的语法
Linux是区分大小文件名的系统,windows是不区分的,变量的话可以加上 $ 进行访问的,也可以使用read 读取用户的输入
read 可以读取不只是一个变量进入,比如
read x y 这样用户就可以输入两个变量了,分隔符还是IFS决定,默认是任意的空白符
引号的使用
双引号内部的内容将会进行”解释翻译“,可以使用转义字符 \ 进行转义
单引号内的内容是原样输出

环境变量
$HOME 当前用户的主目录
$PATH    冒号分割的搜索命令的目录列表
$IFS    输入域分隔符,默认是空格
$$   脚本本身的进程编号
$#    传递给脚本的参数个数
$@    参数的列表
$0    脚本自己的名字
$1    传递给脚本的第一个参数


条件语句
条件需要使用 [] 或者 test 进行测试
if test -f fred.c ; then
...
fi
 
if [ -f fred.c ] ; then
...
fi

字符串的条件测试:
string1 = string2  # 注意不是两个等号,当然也可以用两个等号的形式
string1 != string2
-n string #字符串不为空则为真
-z stirng #字符串为空则为真

算术计算:
expression1 -eq expression2
-ne #not equal
-gt #great than
-ge #great equal
-lt #less than
-le #less equal
! expression #表达式为假则为真

# 强调下,如果使用的是[ ] 里面不能使用 > 这样的运算符逻辑运算符一样,在[ ] 中不能使用 || && 只能用 -a -o 这样的选项 但是 [[ ]] 中没有问题,而且[[ ]] 的效率更高

文件的条件测试:
-d directory
-f file
-r readable
-w writeable
-e executable
-s size # 大小不为零则为真

控制结构:

条件语句

if [ -f /etc/passwd ]
then
    ...
elif [ -f /etc/shadow ] ; then
    ...
fi

for 循环语句

for file in *
  do
      ...
done
exit 0
$($
done


点击(此处)折叠或打开

  1. until语句:循环反复的执行直到条件为真的时候结束

  2.  
  3. 点击(此处)折叠或打开
  4. until conditions
  5.   
  6. do
  7.  
  8.     statements
  9.  
  10. done
  11.  

  12.  
  13.  
  14.  
  15. a=0
  16.  
  17. until [ $a -gt 2 ]
  18.  
  19. do
  20.  
  21. echo $a
  22.  
  23. sleep 1
  24.  
  25. a=$(($a+1)) # 其实这种双括号的写法最靠谱了
  26.  
  27. done


CASE 语句:每个模式的结束处都是(;;)双引号进行结束

点击(此处)折叠或打开

  1. case "$theday" in #注意变量用双引号括起来安全,因为空字符也算是字符串了
  2.   
  3.     yes|y|Y) echo "Your input is yes";; #注意需要双分号进行结尾
  4.  
  5.     no|n|N) echo "Your input is No";;
  6.  
  7.     *) echo "I don't know your input";;
  8.  
  9. esac
  10.  

  11.  
  12.   
  13.  
  14. #通配符要放到最后,因为只会执行第一个符合的条件后就会自动退出,不用break等
  15.  

  16.  
  17.   
  18.  
  19. i=1[ input
  20.  
  21. case "$input" in
  22.  
  23. gaoqiang )yuefuwei)gaoyue|yuegao)*)
  24.  
  25. esac
  26.  
  27. i=$(($i+1));
  28.  
  29. done

逻辑运算
Shell 支持 AND && 计算还有 || OR逻辑或运算,注意的是,这里也采用的短路算法,有可能部分条件都没有进行计算

语句块
可以使用花括号 {  } 构造一个语句块

函数
定义函数之需要写出函数名并写个括号即可
function _name() {
    statemenets
}

Shell 函数不像Pascal和C语言那样存在前置声明,所以是顺序执行的话,就需要将要被调用的函数放到前面,当然也可以使用 local 来声明一个局部变量,局部变量仅在函数内生效,函数内是可以直接访问全局变量。


点击(此处)折叠或打开

  1. yes_or_no() {
  2.         echo "is your name $@:"
  3.         while true
  4.         do
  5.                 echo -n "Enter yes or no"
  6.                 read x
  7.                 case "$x" in
  8.                         yes | y)echo "yes"; return 0;; #多条语句需要使用分号进行分开
  9.                         no | n) echo "no"; return 1;;
  10.                         *) echo "only allow enter yes or no";;
  11.                 esac
  12.         done
  13. }
  14. yes_or_no #函数调用的时候不允许使用括号


命令:
shell中存在两类的命令,一类是shell内部实现的不能被外部的程序调用,另一类是外部命令(external command),大多数的内置命令也提供了单独的程序版本,这是POSIX规范的一部分。

break 和 continue 的使用和C语言的相同,只不过break可以指定需要跳出的层次问题,命令冒号(:)是一条空指令,和Python中的 pass 语句效果相同,同时本身代表True,可以用于逻辑判断
        在老的脚本中冒号还可以用作一行的注释:
if : ; then
: #如果什么都不写直接fi会发生语法错误的
fi

( . )点命令
当一个脚本执行一个新的命令时,它会创建一个新的环境(一个子shell),命令在新的shell中执行,所做的环境更改都会在结束的时候丢弃,只留下退出码返回给父shell。而外部命令 source 和 点命令 在执行脚本的时候,使用的是调用该脚本程序的同一个shell。有点类似C/C++中的#include指令,让子程序在当前的环境中运行,可以使用当前的环境变量等。

echo命令
X/Open建议使用printf命令,默认的echo带有一个换行,可以使用 echo -n 去掉,但是移植性是个问题,可以考虑使用tr进行处理,但是速度较慢,因此最好的移植性还是printf命令。

eval命令
允许对参数进行求值,语法和javascript中的类似【可计算某个字符串,并执行其中的Javascript代码】

点击(此处)折叠或打开

  1. foo=10
  2. x=foo
  3. eval y='$'$x y='$'$x #分别得到 10和 $foo
  4. echo $y


exec命令
将当前的shell替换为一个不同的程序,wall会替换整个脚本,然后exec后面的脚本内容都不会再继续运行
exec wall "that's all,we will finish now"

shift 命令的使用
shift 可以将所有的参数进行左移一位,$3变成 $2,$1本身丢掉,$0 不变还是脚本的名称,直到最后 $1 变成空字符串为止,对于遍历接受的参数非常的有用。

点击(此处)折叠或打开

  1. while [ "$1" != "" ] ;do
  2. echo "$1"
  3. shift
  4. done


export命令
export命令将作为它参数的变量导出到子shell中,并使之在子shell中有效,一旦一个变量被shell到处,它就可以被该shell调用的任何脚本使用,也可以被后续依次调用的任何shell使用,也就是说只能在子shell中使用

expr命令
把它的参数作为一个表达式来求值
x=`expr $x + 1`
x=$(expr $x + 1)
现在建议采用更有效的语法 $(( .. )) 来进行计算

5、Find 命令的详解

语法非常简单 find 需要查找的目录 对应的文件名字或者通配内容 对应的执行命令

find *     #不加目录选项的话则代表当前目录下进行检索
find / -mount -name test     #从根目录下找文件名为test的文件,不要检索挂载的文件系统
-r 进行递归的查找,包括子目录
-i 不对查找的内容区分大小写
可以指定多个路径进行查找 find /tmp /var -name test 

-maxdepths N 指定最深查找的目录深度

访问属性:
-atime N         几天前访问的
-mtime N        几天前修改过
-type c b f d     对应的查找的类型
-user username     属于哪个用户的
-newer x     比x文件要新的文件

条件语句
-a 两个都符合 find / -name test -a -atime 5     # 五天内访问过的名字叫test的文件
-o or语句
! 测试取反的语句

强制改变优先级的话使用(),但是括号需要转义

执行命令比较方便,其中有个魔术变量 {} 代表所有符合条件的结果

-exec command 直接执行对应的命令,同时需要使用 \ 进行结束

find . -newer while2 -type f  -name "*.sh" -exec rm {} \;

查找比while2新且是文件并且后缀是sh的的内容,然后全部删掉【通配符下的文件名必须使用双引号,而且结束的时候需要分号】

阅读(596) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~