码迷,mamicode.com
首页 > 系统相关 > 详细

shell 脚本-符号-基础语法

时间:2016-08-22 23:49:30      阅读:1156      评论:0      收藏:0      [点我收藏+]

标签:linux

为了便于识别  建议 以.sh 结尾

shell脚本 可以放上所有的命令行的指令(源于bash)

shell脚本 是 解释型语言      c/c++ 是编译型语言

下面用到的 shell代码sh_1.sh

#!/bin/bash
cd ../
ls
pwd

解释型脚本的执行过程:

script.sh 是文本文件,根本没有代码段和 _start  函数 , exec 怎么执行。

解释:

Shellfork 一个子进程并调用 exec执行 ./script.sh这个程序,exec 系统调用应该把子进程的代码

段替换成./script.sh程序的代码段 ,并从它的 _start开始执行。然而 script.sh是个文本文件,根 本

没有代码段和 _start函数 ,怎么办呢 ?其实 exec还有另外一种机制 ,如果要执行的是一个文本文

, 并且第一行用 Shebang 指定了解释器 ,则用 解释器程序的代码段替换当前进程 ,并且从解释

器 的_start开始执行 ,而这个文本文件被当作命令行参数传给解释器 。因此, 执行上述脚本相

当于执 行程序

技术分享

1. 交互 Shell(bash)fork/exec一个子 Shell(sh)用于执行脚本 ,父进程 bash等待子进程 sh终止。

2. sh读取脚本中的 cd ..命令 ,调用相应的函数 执行内建命令 ,改变当前工作目录为上一级

目 录。

3. sh读取脚本中的 ls命令 ,fork/exec这个程序 ,列出当前工作目录下的文件 ,sh等待 ls终止。

4. ls终止后 ,sh继续执行 ,读到脚本文件末尾 ,sh终止。

5. sh终止后 ,bash继续执行 ,打印提示符等待用户输入。

如果将命令行下输入的命令用 ()括号括起来 ,那么也会 fork出一个子 Shell执行小括号中的命令 ,

一 行中可以输入由分号 ;隔开的多个命令 ,比如 : $ (cd ..;ls -l)

和上面两种方法执行 Shell脚本的效果是相同的 ,cd ..命令改变的是子 Shell PWD,而不会影响

到 交互式Shell


chmod + x script.sh方式

sh文件中,cd ..命令改变的是子ShellPWD,不会影响到 交互式Shell1(对于文件sh, 交互式shell1会先创建一个子shell2,子shell2会再创建一个shell3,shell3遇见cd命令 会直接由shell2执行,改变的是shell2的路径,shell1的路径不变)

然而source ./script.sh  和 . ./script.sh 方式

则有不同的效果,cd ..命令是直接在交互式Shell1下执行,改变交互ShellPWD

对于php 。。。脚本语言  执行也是 解释器这个流程

sh_1.sh代码:

#!/bin/bash

cd ../

ls

pwd


[bozi@localhost 1_shell]$ /bin/bash sh_1.sh //  shell脚本中 cd   直接在子bash中运行  整个过程父进程 不参与  

1_shell

/home/bozi/linux_test/shell

[bozi@localhost 1_shell]$ pwd

/home/bozi/linux_test/shell/1_shell            //    所以 不影响父进程 的路径   还在子进程的路径中    

[bozi@localhost 1_shell]$ cd ..                //   cd内置命令 shell 自己直接亲自执行(不创建子进程) 影响自己的路径

[bozi@localhost shell]$ pwd

/home/bozi/linux_test/shell                // 直接执行 影响了 跑到上级目录

路径


[bozi@localhost shell]$ ll

总用量 4

drwxrwxr-x. 2 bozi bozi 4096 8月  14 10:18 1_shell

[bozi@localhost shell]$ cd 1_shell/

[bozi@localhost 1_shell]$ ll

总用量 4

-rw-rw-r--. 1 bozi bozi 298 8月  14 10:18 sh_1.sh

source  与(.    命令一样)     

例子:

source  不创建子bash,遇见bash中有内建命令 cd    交互式shell(父进程自己直接执行)    所以 退出时 父进程的路径 变了  影响父进程

[bozi@localhost 1_shell]$ ll

总用量 4

-rw-rw-r--. 1 bozi bozi 298 8月  14 10:18 sh_1.sh

[bozi@localhost 1_shell]$ source sh_1.sh

1_shell

/home/bozi/linux_test/shell

[bozi@localhost shell]$ pwd

/home/bozi/linux_test/shell

.命令 效果相同

[bozi@localhost 1_shell]$ . sh_1.sh

1_shell

/home/bozi/linux_test/shell

[bozi@localhost shell]$ pwd

/home/bozi/linux_test/shell

set 显示 本地变量 和  环境变量(本地变量只存在当前进程中)

env 只显示环境变量   (环境变量 可以传递给 子进程  父子进程共享) 


变量

shell 中  所有变量varname都是字符串 ,且都是全局本地变量     没有int ,float等类型 显示变量 用 $varname或 ${varname}

如果变量不存在    shell显示空串

变量拼接 用{}花括号    如:     ${varname}aaa    $varname"aaa"

演示代码:

[bozi@localhost 2_shell]$ SHELL=1
[bozi@localhost 2_shell]$ echo $SHELL
1
[bozi@localhost 2_shell]$ echo $SHELLabc
[bozi@localhost 2_shell]$ echo ${SHELL}
1
[bozi@localhost 2_shell]$ echo ${SHELL}abc
1abc

unset 取消一个变量

[root@localhost 2_shell]# v=a
[root@localhost 2_shell]# echo $v
a
[root@localhost 2_shell]# unset $v
[root@localhost 2_shell]#

显示本shell的pid

[root@localhost 2_shell]# echo $$
6699

read

-p 提示符  -t 等待的秒数

[bozi@localhost 2_shell]$ read -p ‘>>‘ -t 10 arg
>>nihao
[bozi@localhost 2_shell]$ echo $arg
nihao

数组变量

var[1]="small min"
var[2]="big min"
var[3]="nice min"
echo "${var[1]}, ${var[2]},${var[3]}"
[bozi@localhost 2_shell]$ ./1_test.sh
small min, big min,nice min

test指令

两个整数之间的判定

-eq 相等(equal)

-ne 不等(not equal)

-gt 大于 (greaater than)

-lt 小于 (less than)

-ge 大于等于 (greater than or equal)

-le 小于等于 (less than or equal)

例子:

[bozi@localhost 2_shell]$ test 1 -lt 2; echo $?
0                ---------------》【真】
[bozi@localhost 2_shell]$ test 5 -lt 2; echo $?
1

判定字符串的数据

test -z string [string 为空  返回true]
test -n string [string 为空  返回false]
test str1 = str2 [str1=str2 回传true]
test str1 != str2 [str1 与str2相等返回 false]
例子:
[bozi@localhost 2_shell]$ test -z "";echo $?
0
[bozi@localhost 2_shell]$ test -z "-";echo $?
1
[bozi@localhost 2_shell]$ test -n "";echo $?
1
[bozi@localhost 2_shell]$ test -n "-";echo $?
0
[bozi@localhost 2_shell]$ test "nihao" = "hello" ; echo $?
1
[bozi@localhost 2_shell]$ test "nihao" == "hello" ; echo $?
1
[bozi@localhost 2_shell]$ test "nihao" != "hello" ; echo $?
0

error

[bozi@localhost 2_shell]$ test "nihao"=="hello" ; echo $?

0 ----》“==两边少空格  结果 不正确”

test扩展:

当要检测系统上面某些文件或者是相关的属性时,利用test这个命令来工作真是好用得不得了,如检查/dmtsai是否存在时,使用:test –e /dmtsai

上面的执行结果并不会显示任何信息,但最后可以通过$?或&&及||来显示整个结果。

test –e /dmtsai && echo “exist” ||echo “Not exist”

最终结果可以显示exist还是not exist。-e是测试一个东西存在不存在。常用的测试命令如下:


测试的标志

代表意义

关于某个文件名的“文件类型”判断,如test – e filename表示存在否

-e

该文件名是否存在

-f

该文件名是否存在且为文件(file)

-d

该文件名是否存在且为目录(directory)

-b

该文件名是否存在且为一个block device设备

-c

该文件名是否存在且为一个character device设备

-S

该文件名是否存在且为一个Socket文件

-p

该文件名是否存在且为一个FIFO(pipe)文件

-L

该文件名是否存在且为一个连接文件

关于文件的权限检测,如test –r filename表示可读否(但root权限常有例外)

-r

检测该文件名是否存在且具有“可读”的权限

-w

检测该文件名是否存在且具有“可写”的权限

-x

检测该文件名是否存在且具有“可执行”的权限

-u

检测该文件名是否存在且具有“SUID”的属性

-g

检测该文件名是否存在且具有“SGID“的属性

-k

检测该文件名是否存在且具有“Sticky bit”的属性

-s

检测该文件名是否存在且具有“非空白文件”

两个文件之间的比较,如test file1 –nt file2

-nt

(newer than)判断file1是否比file2新

-ot

(older than)判断file1是否比file2旧

-ef

判断file1与file2是否为同一文件,可用在判断hard link的判定上。主要意义在于判定两个文件是否均指向同一个inode

关于两个整数之间的判定吗,如test n1 –eq n2

-eq

两数值相等(equal)

-ne

两数值不等(not equal)

-gt

N1大于n2(greate than)

-lt

N1小于n2(less than)

-ge

N1大于等于n2(greater than or equal)

-le

N1小于等于n2(less than or equal)

判定字符串的数据

test –z string

判定字符串是否为0,若string为空字符串,则为true

test –n string

判定字符串是否非为0,若string为空字符串,则为false

test str1 = str2

判定str1是否等于str2,若相等,则回传true

test str1 != str2

判定str1是否不等于str2,若相等,则回传false

多重条件判定,若test –r filename –a –x filename

-a

两个条件同时成立!如test –r file –a –x file,则file同时具有r与x权限时,才回传true

-o

任何一个条件成立!如test –r file –o –x file,则file具有r或x权限时,就可回传true

反向状态,如test ! –x file,但file不具有x时,回传true

多重条件判定

-a [先当于 与&&]

-o 【或】

! 【非】

 例子:

[bozi@localhost 2_shell]$ test 1 -eq 1 -a 2 -lt 5; echo $?
0
[bozi@localhost 2_shell]$ test 1 -eq 1 -a 5 -lt 2; echo $?
1

判断符号[]

[bozi@localhost 2_shell]$ [ "" ==  "HOME" ];echo $?
1
[bozi@localhost 2_shell]$ [ "" !=  "HOME" ];echo $?
0


error

[bozi@localhost 2_shell]$ [ ""!="HOME" ];echo $?
0
[bozi@localhost 2_shell]$ [ ""=="HOME" ];echo $?
0

注意  空格不能少  否则出错:

[bozi@localhost 2_shell]$ [ 空格"" 空格==  空格"HOME" 空格];echo $?

建议:

1 在中括号[]中的每个组件用 空格 隔开

2 在中括号内的变量, 最好用双引号括起来

3 在中括号里面的常量最好用单引号或 双引号括起来

2的一个错误例子:

[bozi@localhost 2_shell]$ name="hello world"
[bozi@localhost 2_shell]$ [ $name == "hello" ]
bash: [: too many arguments   --------------------------》  太多参数 本来是两个参数比较 因为name变量的字符串中间有空格 不加“”
解析为 [ hello world == "hello" ]   肯定参数太多
[bozi@localhost 2_shell]$ [ "$name" == "hello" ]
[bozi@localhost 2_shell]$ echo $?
1
[bozi@localhost 2_shell]$ [ "$name" != "hello" ]
[bozi@localhost 2_shell]$ echo $?
0

小练习:

read -p "please inoput (Y/N):" yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "ok, continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "oh, interrupt" && exit 0
echo "I dont know what your chonice is " && exit 0
运行:
[bozi@localhost 2_shell]$ ./1_test.sh
please inoput (Y/N):y
ok, continue
[bozi@localhost 2_shell]$ ./1_test.sh
please inoput (Y/N):n
oh, interrupt
[bozi@localhost 2_shell]$ ./1_test.sh
please inoput (Y/N):
I dont know what your chonice is

shell中&&和||的使用方法

&&运算符:

 

command1  && command2

 

&&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行;换句话说,“如果这个命令执行成功&&那么执行这个命令”。 

语法格式如下:

 

    command1 && command2 [&& command3 ...]

 

1 命令之间使用 && 连接,实现逻辑与的功能。

2 只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才会被执行。

3 只要有一个命令返回假(命令返回值 $? == 1),后面的命令就不会被执行。

||运算符:

command1 || command2

 

||则与&&相反。如果||左边的命令(命令1)未执行成功,那么就执行||右边的命令(命令2);或者换句话说,“如果这个命令执行失败了||那么就执行这个命令。

1 命令之间使用 || 连接,实现逻辑或的功能。

2 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才会被执行。这和 c 语言中的逻辑或语法功能相同,即实现短路逻辑或操作。

3 只要有一个命令返回真(命令返回值 $? == 0),后面的命令就不会被执行。

&& || 与 -a -o

区别

-a -o 连接的是两个表达式 即 测试条件

而 && 与 || 连接的是两条 命令

代码:

val=10
str="hello"
test $val -eq 10 -a "$str" == "hello"
echo $?
test $val -eq 10 && test "$str" == "hello"
echo $?
运行:
[bozi@localhost 2_shell]$ ./12_test.sh
0
0

默认变量  $0 $1 $2 ...

例子:$ ./1_test.sh nihao sunshine

                     $0        $1        $2

$# :代表后接的参数的个数, 如上例子为2

$@:代表"$1" "$2" ... 之意, 每个变量独立的用双括号括起来

$*: 代表“$1c$2c$3c$4” c为分隔符号,默认是空格键

          $@ 和 $*还是有所不同的 一般用 $@

代码:

#! /bin/bash
echo "\$0 is $0"
echo "\$1 is $1"
echo "\$2 is $2"
echo "\$# is $#"
echo "\$@ is $@"
echo "\$* is $*"

运行:

[bozi@localhost 2_shell]$ ./1_test.sh
$0 is ./1_test.sh
$1 is
$2 is
$# is 0
$@ is
$* is
[bozi@localhost 2_shell]$ ./1_test.sh 1 2 3 4
$0 is ./1_test.sh
$1 is 1
$2 is 2
$# is 4
$@ is 1 2 3 4
$* is 1 2 3 4

代码:

echo "your whole parameter is ===>$0"
echo "total parameter numbers is ===>$#"
[ "$#" -lt 2 ]&&echo "the numbers of paramater is less than 2. stop here"&& exit 0;
echo "your whole parameter is ===>$@"
echo "the 1st parameter ===>$1"
echo "the 2nd parameter ===> $2 "

运行:

[bozi@localhost 2_shell]$ ./1_test.sh
your whole parameter is ===>./1_test.sh
total parameter numbers is ===>0
the numbers of paramater is less than 2. stop here
[bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine
your whole parameter is ===>./1_test.sh
total parameter numbers is ===>2
your whole parameter is ===>nihao sunshine
the 1st parameter ===>nihao
the 2nd parameter ===> sunshine

运行:

[bozi@localhost 1_shell]$ cat sh_1.sh
 #!/bin/bash
myint=10
echo ‘\$ \\ $myint \"‘
echo ‘###############‘
echo "\$ \\ $myint \""
[bozi@localhost 2_shell]$ ./1_test.sh
your whole parameter is ===>./1_test.sh
total parameter numbers is ===>0
the numbers of paramater is less than 2. stop here
[bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine
your whole parameter is ===>./1_test.sh
total parameter numbers is ===>2
your whole parameter is ===>nihao sunshine
the 1st parameter ===>nihao
the 2nd parameter ===> sunshine
[bozi@localhost 2_shell]$ ./1_test.sh nihao sunshine here
your whole parameter is ===>./1_test.sh
total parameter numbers is ===>3
your whole parameter is ===>nihao sunshine here
the 1st parameter ===>nihao
the 2nd parameter ===> sunshine

shift:造成参数号码偏移,移除前num个参数

shift+num  num 及num之前的参数全部移除   num之后的参数从$1开始 

如:

echo $@
echo "arg count $#"
shift 1
echo "after shift 1"
echo $@
echo "arg count $#"
shift 3
echo "after shift 3"
echo $@
echo "arg count $#"

运行:

[bozi@localhost 2_shell]$ ./1_test.sh one two three four five six seven
one two three four five six seven
arg count 7
after shift 1
two three four five six seven
arg count 6
after shift 3
five six seven
arg count 3

条件判断式

1 if ... then

if [条件判断式];then 

     条件成立执行

fi 

&&代表AND

|| 代表 or

代码:

#!/bin/bash
read -p "please input (Y/N):" yn
if [ "X$yn" == "XY" ] || [ "X$yn" == "Xy" ];then
    echo "ok, continue"
    exit 0
fi
if [ "X$yn" == "XN" ] || [ "X$yn" == "Xn" ];then
        echo "oh, interupt!"
        exit 0
fi

运行:

please input (Y/N):y
ok, continue
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):Y
ok, continue
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):N
oh, interupt!
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):n
oh, interupt!

多重复杂条件判断式

if [条件判断式];then

     条件成立

else

     ...

if

if [条件判断式1];then 

     ...

elif [条件判断式2];then

     ...

else

     ...

if

代码:

read -p "please input (Y/N):"  yn
if [ "x$yn" == "xY" ] || [ "x$yn" == "xy" ]; then
    echo "ok, continue"
elif [ "x$yn" == "xN" ] || [ "x$yn" == "xn" ]; then
    echo "oh, interupt"
else
    echo "I dont know what your choice is"
fi

运行:

[bozi@localhost 2_shell]$ vim 2_test.sh
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):y
ok, continue
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):n
oh, interupt
[bozi@localhost 2_shell]$ ./2_test.sh
please input (Y/N):s
I dont know what your choice is
代码:
testing=$(netstat -tuln |grep ‘:80‘ )
if [ "X$testing" != "X" ];then
    echo "WWW is running in your system ."
fi
testing=$(netstat -tuln | grep ‘:22‘)
if [ "X$testing" != "X" ]; then
    echo "SSH is running in your system."
fi
testing=$(netstat -tuln | grep ‘:21‘)
if [ "X$testing" != "X" ]; then
    echo "FTP is running in your system."
fi
testing=$(netstat -tuln | grep ‘:25‘)
if [ "X$tesing" != "X" ]; then
    echo "Mail is running in your system."
fi

运行:

[bozi@localhost 2_shell]$ ./3_text.sh
Now, I will detect your linux server‘s services!
The wwww, ftp, ssh , and mail will be detect !
SSH is running in your system.

利用case ......  esac判断

case $变量名称 in

     ”第1个变量名称“)

                    程序段

               ;; 

     ”第2个变量名称“)

                    程序段

               ;;                                      # ;; 相当于break

         

     *)                                                 #*)相当于default

                    程序段

               ;; 

esac

代码:

#!/bin/bash
case $1 in
    "one")
        echo "your choice is ONE"
        ;;
    "two")
        echo "your choice is TWO"
        ;;
    "three")
        echo "your choice is THREE"
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac

运行:

[bozi@localhost 2_shell]$ ./4_test.sh
Usage ./4_test.sh {one|two|three}
[bozi@localhost 2_shell]$ ./4_test.sh one
your choice is ONE
[bozi@localhost 2_shell]$ ./4_test.sh two
your choice is TWO
[bozi@localhost 2_shell]$ ./4_test.sh three
your choice is THREE

函数 function

函数的参数 也是$1$2$....    但是函数体里面的$1$2...与函数外面的 是相对独立的

函数返回值: return后    用  $? 来接收  【返回值】(缺陷  返回257   是 1        范围0-255)

代码:

#!/bin/bash
function printit()             # 也可以不加关键字function  即  printit(){...}   也是可以的
{
    echo -n "Your choice is "  #加上-n表示不断行继续在一行显示
}
case $1 in
    "one")
        printit;echo $1 |tr ‘a-z‘ ‘A-Z‘ #大小写转化
        ;;
    "two")
        printit;echo $1 |tr ‘a-z‘ ‘A-Z‘ #大小写转化
        ;;
    "three")
        printit;echo $1 |tr ‘a-z‘ ‘A-Z‘ #大小写转化
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac

运行:

[bozi@localhost 2_shell]$ ./5_test.sh one
Your choice is ONE
[bozi@localhost 2_shell]$ ./5_test.sh
Usage ./5_test.sh {one|two|three}
[bozi@localhost 2_shell]$ ./5_test.sh one
Your choice is ONE
[bozi@localhost 2_shell]$ ./5_test.sh two
Your choice is TWO
[bozi@localhost 2_shell]$ ./5_test.sh three
Your choice is THREE

经典的fork炸弹   【!!!立马宕机】

.() { .|.& }; .             #递归调用  后台执行

类似的  function a() { a|a }; a

防范措施 ulimit -Hu num  限定用户最多num个进程

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

以下程序段就是由Jaromil所作的在类UNIX系统的shell环境下触发fork炸弹的shell脚本代码,总共只用了13个字符(包括空格):

:(){ :|:& };:

注解如下:

:() # 定义函数,函数名为":",即每当输入":"时就会自动调用{}内代码

# ":"函数开始标识

# 用递归方式调用":"函数本身

# 并用管道(pipe)将其输出引至...

# 另一次递归调用的":"函数

# 综上,":|:"表示的即是每次调用函数":"的时候就会生成两份拷贝【二倍指数增长】

# 调用间脱钩,以使最初的":"函数被杀死后为其所调用的两个":"函数还能继续执行

# ":"函数结束标识

# ":"函数定义结束后将要进行的操作...

# 调用":"函数,"引爆"fork炸弹

其中函数名“:”只是简化的一例,实际实现时可以随意设定,一个较易理解(将函数名替换为“forkbomb”)的版本如下:

forkbomb(){ forkbomb|forkbomb &} ; forkbomb

Windows下则可以批处理命令如下实现:

%0|%0

POSIX标准下的C与C++的实现:

#include <unistd.h>int main(){while(1) fork();return0;}

Perl语言的实现:

fork while fork

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

循环

while do done, until do done(不定循环)

代码:

#!/bin/bash
while [ "X$yn" != "Xyes" -a "X$yn" != "XYES" ]
do
    read -p "please input yes/YES to stop this program:" yn
done
echo "ok, you input the correct answer."

运行:

[bozi@localhost 2_shell]$ chmod u+x 6_test.sh
[bozi@localhost 2_shell]$ ./6_test.sh
please input yes/YES to stop this program:e
please input yes/YES to stop this program:e
please input yes/YES to stop this program:yes
ok, you input the correct answer.

until代码:

sum=0
i=0
until [ $i -gt 100 ]
do
    if (( i%2==0 ));then
    let sum+=i
    fi:
    let i++
done
echo $sum

运行:

[bozi@localhost 2_shell]$ ./6_test.sh
2550
代码:
s=0
i=0
while [ "$i" != "100" ]
do
    i=$(($i+1))
    s=$(($s+$i))
done
echo "sum of 1+2+3+...+100 is : $s"

运行:

[bozi@localhost 2_shell]$ ./7_test.sh
sum of 1+2+3+...+100 is : 5050

for ... do... done(固定循环)

for var in con1 con2 con3 ...

do

     程序段

done

代码:

for animal in dog cat elephant
do
    echo "there are ${animal}s..."
done
运行:
[bozi@localhost 2_shell]$ ./8_test.sh
there are dogs...
there are cats...
there are elephants...

代码:

users=$(cut -d‘:‘ -f1 /etc/passwd)
for username in $users
do
    id $username
done

运行:

[bozi@localhost 2_shell]$ ./9_test.sh
uid=0(root) gid=0(root) 组=0(root)
uid=1(bin) gid=1(bin) 组=1(bin),2(daemon),3(sys)
uid=2(daemon) gid=2(daemon) 组=2(daemon),1(bin),4(adm),7(lp)
uid=3(adm) gid=4(adm) 组=4(adm),3(sys)
uid=4(lp) gid=7(lp) 组=7(lp)
uid=5(sync) gid=0(root) 组=0(root)

测ip代码:

read -p "enter like 192.168.1->" network
for sitenu in $(seq 1 100)
do
ping -c 1 -w 1 ${network}.${sitenu} &>/dev/null && result=0 || result=1
if [ "$result" == 0 ];then
echo "server ${network}.${sitenu} is up."
else
echo "server ${network}.${sitenu} is down"
fi
done

运行:

[bozi@localhost 2_shell]$ ./9_test.sh
enter like 192.168.1->192.168.174
server 192.168.174.1 is up.
server 192.168.174.2 is up.
server 192.168.174.3 is down
server 192.168.174.4 is down
server 192.168.174.5 is down
server 192.168.174.6 is down
server 192.168.174.7 is down

代码:

#!/bin/bash
read -p "please input a diretory:" dir
if [ "$dir" == "" -o ! -d "$dir" ];then
    echo "then $dir is not exist in your system."
    exit 1
fi
filelist=$(ls $dir)
for filename in $filelist
do
    perm=""
    test -r "$dir/$filename" && perm="$perm readable"
    test -w "$dir/$filename" && perm="$perm writable"
    test -x "$dir/$filename" && perm="$perm executable"
    echo "the file $dir/$filename‘s permission is $perm"
done

运行:

[bozi@localhost 2_shell]$ ./10_test.sh
please input a diretory:../1_shell
the file ../1_shell/2‘s permission is  readable writable
the file ../1_shell/3‘s permission is  readable writable
the file ../1_shell/sh_1.sh‘s permission is  readable writable
the file ../1_shell/sh_2.sh‘s permission is  readable writable executable


for ....do...done 的数值处理

for ((初始值; 限制值;执行步阶))

do

     程序段     

done

这种写法 适合在数值运算中

代码:

read -p "please input a number . I will count for 1+2+3+...+your_input" num
s=0
for ((i=1; i <= $num; i++))
do
    ((s += i))
done
echo "the result of ‘1+2+3+...+$num ‘is $s"

 运行:

[bozi@localhost 2_shell]$ ./11_test.sh
please input a number . I will count for 1+2+3+...+your_input10
the result of ‘1+2+3+...+10 ‘is 55
代码:
#!/bin/bash
for i in {A..b}
do
    echo "val is: $i"
done

运行:

[bozi@localhost 2_shell]$ sh 14_test.sh
val is: A
val is: B
val is: C
val is: D
val is: E
val is: F
val is: G
val is: H
val is: I
val is: J
val is: K
val is: L
val is: M
val is: N
val is: O
val is: P
val is: Q
val is: R
val is: S
val is: T
val is: U
val is: V
val is: W
val is: X
val is: Y
val is: Z
val is: [
val is:
val is: ]
val is: ^
val is: _
val is: `
val is: a
val is: b

shell script 的  追踪 与  debug

-n : 不执行script,仅查询语法错误

-v: 在执行script之前,现将script的内容输出到屏幕上

-x: 将使用到的script内容显示到屏幕上

代码:

检查是否有语法问题    没有问题就什么也不输出

运行:

[bozi@localhost 2_shell]$ sh -n 12_test.sh

[bozi@localhost 2_shell]$

代码:

将使用到的代码显示出来

运行:

[bozi@localhost 2_shell]$ sh -x 12_test.sh
+ val=10
+ str=hello
+ test 10 -eq 10 -a hello == hello
+ echo 0
0
+ test 10 -eq 10
+ test hello == hello
+ echo 0
0

一是在命令行提供参数

$ sh -x ./script.sh

二是在脚本开头提供参数

#! /bin/sh -x

第三种方法是在脚本中用 set命令启用或禁用参数

set -xset +x 分别表示启用和禁用 -x参数 ,这样可以只对脚本中的某一段进行跟踪调试。

代码:

val=10
str="hello"
set -x
test $val -eq 10 -a "$str" == "hello"
echo $?
set +x
test $val -eq 10 && test "$str" == "hello"
echo $?

运行:

[bozi@localhost 2_shell]$ sh -x 12_test.sh
+ val=10
+ str=hello
+ set -x
+ test 10 -eq 10 -a hello == hello
+ echo 0
0
+ set +x
0

:是一个特殊的命令,称为空命令 ,该命令不做任何事, Exit Status总是真。此外 ,也可以执 行

/bin/true或 /bin/false得到真或假的 Exit Status。


文件名替换

这些用于匹配的字符称为通配符 (Wildcard),具体如下 :

通配符 * : 匹配 0个或多个 任意字符

? : 匹配 一个任意 字符

[若干字符 ] : 匹配 方括号中任意一个字符的一次出现

运行:
[bozi@localhost 1_shell]$ ls *
2  3  sh_1.sh  sh_2.sh
[bozi@localhost 1_shell]$ ls sh_?.sh
sh_1.sh  sh_2.sh
[bozi@localhost 1_shell]$ ls [s]h*
sh_1.sh  sh_2.sh

注意, Globbing 所匹配的文件名是由 Shell展开的 ,也就是说在参数还没传给程序之前已经展开

了 ,不是ls展开的

命令代换:

由反引号``括起来的也是一条命令 ,Shell先执行该命令 ,然后将输出结果立刻代换到当前命令行

中。

[bozi@localhost 1_shell]$ DATE=‘date‘
[bozi@localhost 1_shell]$ echo $DATE
date
[bozi@localhost 1_shell]$ DATE=`date`
[bozi@localhost 1_shell]$ echo $DATE
2016年 08月 21日 星期日 11:05:13 CST

例如定义一个变量存放 date命令的输出 :

命令代换也可以用 $()表示 : $ DATE=$(date)

[bozi@localhost 1_shell]$ DATE=$(date)
[bozi@localhost 1_shell]$ echo $DATE
2016年 08月 21日 星期日 11:05:56 CST


算术代换 :$(())

用于算术计算 ,$(())中的 Shell变量取值将转换成整数 ,例如 :

[bozi@localhost 1_shell]$ v=3
[bozi@localhost 1_shell]$ echo $((v+3))
6

$(())只能用+-*/ ()运算符 ,并且只能做整数运算。


(( )) 中间支持c语言的写法

[bozi@localhost 1_shell]$ i=1;(( i++));echo $i
2
[bozi@localhost 1_shell]$ i=1;(( i+=5));echo $i
6
[bozi@localhost 1_shell]$ i=1;(( i>0));echo $?
0
[bozi@localhost 1_shell]$ i=1;(( i<0));echo $?
1

shell进度条小程序

代码:

#!/bin/bash
function proc()
{
    i=0;
    str=‘‘
    arr=(‘|‘ ‘/‘ ‘-‘ ‘\\‘)
    index=0
    while [ $i -le 100 ]
    #while ((i <= 100))
    do
        printf "[%-100s][%d%%][%c]\r" "$str" "$i" "${arr[$index]}"
    #这里不用像c语言一样fflush刷新输出缓冲区 因为 printf是子进程执行
    # 子进程退出自动刷新
        str=${str}‘#‘
        sleep 0.1
        let i++
        let index++
        let index%=4
        #((index%=4))
    done
    printf "\n"
}
function main()
{
    proc
}
main

运行:

[bozi@localhost 4_shell]$ sh proc.sh
#########################################################################                          ][74%][-]

读取文件数据  计算最大和最小值、平均值

代码:

#找 文件中的最大值和 最小值

max=0
min=0
count=0
sum=0
while read line
do
    if [ "$count" -eq "0" ];then
        max=$line
        min=$line
        let count++
        let sum+=$line
        continue
    fi
    [ "$max" -lt "$line" ] && max=$line
    [ "$min" -gt "$line" ] && min=$line
    let sum+=$line
    let count++
done <file
echo $max
echo $min
echo "ibase=10 ;scale=2; $sum/$count" | bc

数据:

[bozi@localhost 4_shell]$ cat file
1
2
3
4
5
6
7
8
9

运行:

[bozi@localhost 4_shell]$ sh ./5_shell.sh
9
1
5.00

建议数字计算 用(())  不用[  ]    []对于空数据报错

如数据第四行空  

file
[bozi@localhost 4_shell]$ cat file
1
2
3
5
6
7
8
9

(())结果    

  

  if (( line <  9));then
[bozi@localhost 4_shell]$ vim test.sh
[bozi@localhost 4_shell]$ sh  ./test.sh
1
2
3
5
6
7
8
error

[]结果 if [ "$line" -lt  "9" ];then

[bozi@localhost 4_shell]$ sh  ./test.sh
1
2
3
./test.sh: line 11: ((: <  9 : syntax error: operand expected (error token is "<  9 ")
error
5
6
7
8
error

数组

1 数组的定义 

一对()表示数组 数组元素用 空格 符号作为分隔符

[bozi@localhost 4_shell]$ a=(1 2 3 4 5)
[bozi@localhost 4_shell]$ echo $a
1
[bozi@localhost 4_shell]$ echo ${a[*]}
1 2 3 4 5
[bozi@localhost 4_shell]$ str=(‘q‘ "nihao" ‘hello‘)
[bozi@localhost 4_shell]$ echo $str
q
[bozi@localhost 4_shell]$ echo ${str[@]}
q nihao hello

2 数组的读取与赋值(下标从0开始)

赋值:

[bozi@localhost 4_shell]$ a[10]=10

读取:

[bozi@localhost 4_shell]$ echo ${a[*]}
1 2 3 4 5 10
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 10

得到长度:

得到整个数组长度

[bozi@localhost 4_shell]$ echo ${#a[*]}
6
[bozi@localhost 4_shell]$ echo ${#a[@]}
6

得到数组某个元素的长度

[bozi@localhost 4_shell]$ a=(1 2 3 4 5 10)
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 10
[bozi@localhost 4_shell]$ echo ${#a[5]}
2
[bozi@localhost 4_shell]$ echo ${#a[0]}
1

删除:

[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 10

#删除某个元素

[bozi@localhost 4_shell]$ unset a[2]
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 4 5 10

#删除整个数组

[bozi@localhost 4_shell]$ unset a
[bozi@localhost 4_shell]$ echo ${a[@]}
[bozi@localhost 4_shell]$

3.特殊使用:

分片:

$[数组名{@或*]起始位置:长度} 从起始位置开始 切长度个元素

返回的是字符串  中间用空格隔开

所以如果加上"()" , 将的到切片的数组。

[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 6
[bozi@localhost 4_shell]$ echo ${a[@]:0:3}
1 2 3
[bozi@localhost 4_shell]$ echo ${a[@]:2:3}
3 4 5
[bozi@localhost 4_shell]$ echo ${a[@]:2:5}
3 4 5 6
[bozi@localhost 4_shell]$ echo ${a[@]:1:5}
2 3 4 5 6

加上"()" , 将的到切片的数组。

[bozi@localhost 4_shell]$ echo ${a[@]:1:5}
2 3 4 5 6
[bozi@localhost 4_shell]$ newa=(${a[@]:1:5})
[bozi@localhost 4_shell]$ echo ${newa[@]}
2 3 4 5 6

替换:

调用方法是: ${数组名[@或*]/查找字符/替换字符} 该操作不会改变原先的内容, 如果需要修改, 可以像上面一样  加() 生成一个新的数组

[bozi@localhost 4_shell]$ a=(1 2 3 4 5 6)
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 6
[bozi@localhost 4_shell]$ echo ${a[@]/3/100}
1 2 100 4 5 6
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 3 4 5 6

原内容 未改变

要改变原内容 加()

[bozi@localhost 4_shell]$ a=(${a[@]/3/100})
[bozi@localhost 4_shell]$ echo ${a[@]}
1 2 100 4 5 6
[bozi@localhost 4_shell]$ str=("nihao" hello)
[bozi@localhost 4_shell]$ echo ${str[@]}
nihao hello
[bozi@localhost 4_shell]$ echo ${str[@]/ni/wo}
wohao hello
[bozi@localhost 4_shell]$ str=("nihao" "hello" "here")
[bozi@localhost 4_shell]$ echo ${str[@]}
nihao hello here
[bozi@localhost 4_shell]$ echo ${str[@]/he/the}
nihao thello there

遍历数组:

arr=(aaa bbb ccc ddd)
num=${#arr[@]}
for ((i = 0; i < num; i++))
    {
        echo ${arr[i]}
    }
[bozi@localhost 4_shell]$ sh arr.sh
aaa
bbb
ccc
ddd

特殊

arr=(aaa bbb ccc ddd)
arr[50]="ffff"
num=${#arr[*]}
for ((i = 0; i < num; i++))
    {
        echo ${arr[i]}
    }

结果  多了一个元素arr[50]  读也是读五个 只不过是从前向后读 没有读到arr[50] 读到空

这里${#arr[*]}和 ${#arr[@]}都是5

[bozi@localhost 4_shell]$ sh arr.sh
aaa
bbb
ccc
ddd
[bozi@localhost 4_shell]$ cat arr.sh

下面这种方式解决读到空的问题 没有读到后面的有效数字

代码:

arr=(aaa bbb ccc ddd)
arr[50]="ffff"
num=${#arr[*]}
for var in ${arr[*]}
#for var in ${arr[@]}       这两个效果一样 都能访问到定义了的数据

{
        echo $var
    }

运行:

[bozi@localhost 4_shell]$ sh arr.sh
aaa
bbb
ccc
ddd
ffff
[bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$ arr[100]="iam100"
[bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done
a
b
c
hello
iam100
[bozi@localhost 4_shell]$ [bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$ arr[100]="iam100"
[bozi@localhost 4_shell]$ for var in ${arr[*]}; do echo $var;let i++;done
a
b
c
hello
iam100
[bozi@localhost 4_shell]$ for var in ${arr[@]}; do echo $var;let i++;done
a
b
c
hello
iam100
[bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[*]})); do echo ${arr[i]};let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[@]})); do echo ${arr[i]};let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$
${arr[@]}; do echo $var;let i++;done
a
b
c
hello
iam100
[bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[*]})); do echo ${arr[i]};let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$ i=0;while ((i < ${#arr[@]})); do echo ${arr[i]};let i++;done
a
b
c
hello
[bozi@localhost 4_shell]$

从这个 例子可以看出 

for var in种方式访问的是 有效元素的个数

for ((i = 0; i < len;i++)) 是从前向后找 ,找len个就停止,后面隔着的有些有效的数据就没有输出


count=0; while [ $count -le 100] touch test${count};

数学运算((  ))中变量直接取得是 变量的值

v1=1

v2=2

((v3 = v1 + v2))    //    (($v3 = $v1 + $v2)) 也可以

echo $(v3)

echo $(arr[*])   显示所有的元素 (空的丢弃)

echo $(arr[@])   显示所有的元素

echo $(#arr[@]) 显示 已经定义的元素的个数    如   arr

遍历数组

for i in $(arr[@])

do

     echo $(arr[i])

done


单引号 双引号

单引号 对转义、特殊的变量 都不会 进行处理  原样输出

双引号                                      会处理              

 [bozi@localhost 1_shell]$ /bin/bash sh_1.sh

10

\$ \\ $myint \"

###############

$ \ 10 "

 


本文出自 “城市猎人” 博客,请务必保留此出处http://alick.blog.51cto.com/10786574/1841148

shell 脚本-符号-基础语法

标签:linux

原文地址:http://alick.blog.51cto.com/10786574/1841148

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!