Shell 命令学习

Posted by 撒得一地 on 2016年5月5日 in Linux笔记

Shell脚本是非常强的大一个脚本语言,但是不用会手生,所以在此记录Shell脚本的相应关键点,也做查字典用^_^变量。

变量

变量定义

先来简单的看一下变量定义的规则

  1. Shell中,使用变量之前不需要事先声明,只是通过使用它们来创建它们;
  2. 在默认情况下,所有变量都被看做是字符串,并以字符串来存储;
  3. Shell变量是区分大小写的;
  4. 在赋值变量的时候等号两端不能有空格-_-

定义了变量之后,一定要加上$符号才能使用

1
2
3
4
5
6
7
8
9
10
11
12
#! /bin/bash

VAR1=HELLO
VAR2=MY NAME
VAR3="MY AGE"
VAR4 = IS

echo VAR1 #error 能输出 但不是输出该变量
echo $VAR1 #ok 正常读取变量并打印
echo $VAR2 #error 定义变量的值 用空格隔开了
echo $VAR3 #ok 作为一整个字符串
echo $VAR4 #error 变量定义的时候等号两端有空格

输出的结果为

./test.sh: line 2: NAME: command not found
./test.sh: line 4: VAR4: command not found
VAR1
HELLO

MY AGE

关于shell脚本的执行:shell基本一般是以.sh为后缀,然后在*unix系统下一般都是直接使用./[当前shell文件名] 的方式来执行,也可以使用全部经/[shell文件名]的方式来执行,并且需要注意的是 被执行的shell文件一定是有含有可执行权限了的,可以使用chmod命令来修改

还有另一个点就是在调用变量的时候 ,如果在双引号中直接使用$name任然可以识别,但是如果在单引号是就无法适用$name的方式来调用变量

read读取输入值

这个功能就像java中的readline来读取,使用方法为

1
2
3
4
5
6
7
#! /bin/bash

echo "whats your name?"
read NAME  #在这里读取输入值到NAME变量中 ,这里如果不输入会停留在屏幕上
echo "webcome back" $NAME

exit 0

可以看到熟悉的结果为

whats your name?
tom
webcome back tom

环境变量

Shell脚本还提供能一些实用的环境变量

  1. $HOME:为当前用户所在的目录
  2. $PATH:当前用户所能方法的PATH变量
  3. $#:传递参数额个数 类似java中的args.length
  4. $$:Shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件。
1
2
3
4
5
6
7
8
9
#! /bin/bash

echo "当前用户所在的目录为" $HOME
echo "当前的执行目录为" $(pwd)  #这个是访问当前的脚本的目录很实用
echo "当前用户所能访问的PATH为" $PATH
echo "当前参数的参数个数为" $#  #这儿参数的格式是使用空格隔开的哦
echo "当前Shell脚本的进程号为" $$

exit 0

可以到看的结果是

yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  hello world
当前用户所在的目录为 /Users/yanyl
当前的执行目录为 /Users/yanyl/Downloads
当前用户所能访问的PATH为 /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/yanyl/Program/apache-maven-3.2.5/bin:/Users/yanyl/Program/scala-2.10.4//bin
当前参数的参数个数为 2
当前Shell脚本的进程号为 43746

假如需要进入当前目录的父目录,可以使用$(dirname $(pwd))

参数变量

刚刚看到可以使用read关键字可以来读取输入变量,但是我们可能更加常用的是参数变量,也就是$#的个数,它的规则如下

  1. $#表示参数变量的个数
  2. $0表示当前的脚本名称
  3. $1,$2…$n表示依次能读取到的变量 但是如果参数变量不够,$i会被赋值为空
1
2
3
4
5
6
7
8
9
#! /bin/bash

echo "当前输入的参数变量的长度为" $#
echo "当前执行的Shell脚本为" $0
echo "当前输入的第一个参数为" $1
echo "当前输入的第二个参数为" $2
echo "当前的输入的第三个参数为" $3 #现在如果只传2个参数 这里将不会报错

exit 0

可以看到的结果为

yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  hello world
当前输入的参数变量的长度为 2
当前执行的Shell脚本为 ./hi.sh
当前输入的第一个参数为 hello
当前输入的第二个参数为 world
当前的输入的第三个参数为

可以看到在Shell脚本中去读取参数变量还是很方便的,这样配合下面的条件判断以及循环就可以做很多事情了

读取返回码

一般的程序/命令在执行结束时都会返回一个 返回码,比如

  • javasystem.exit(-1)
  • pythonsys.exit(-1)
  • 还有上面Shell脚本中的最后一行exit 0

如果你不显式指定返回码,一般默认为0,表示正常退出,但是有时候显式的指定返回码是一个好习惯哦

这些程序在Shell中执行的,可以使用$?来读取上一个程序执行下来的脚本码

1
2
3
4
5
6
7
8
9
#! /bin/bash

du -s #执行的返回码一般为0
echo du -s的返回码为 $?

duu -s #这个命令故意输错
echo duu -s的返回码为 $?

exit 0

可以看到正确的结果为

28494656    .
du -s的返回码为 0
./hi.sh: line 6: duu: command not found
duu -s的返回码为 127

返回码配上if判断,就可以使用shell脚本自由得在各个语言以及命令中穿梭啦^_^

数学运算

在上一小节中说道,Shell中变量一般都是当字符串来处理,那我遇到数字运算该咋办呢??

可以先看

1
2
3
4
5
6
7
8
#! /bin/bash

a=1+2
b=$a+3
echo $a
echo $b

exit 0

结果却看到

1+2
1+2+3

那在Shell中解决这个问题大概有这么几种方法

let关键字

1
2
3
4
5
6
7
8
#! /bin/bash

let a=1+2
let b=$a+3
echo $a
echo $b

exit 0

输出的结果为

3
6

这个关键词大致需要注意以下几个点:

  • let只支持整数运算
  • let后面的运算部分有bash关键字时,需加双引号
  • 幂次方可以使用**符号

使用(())

1
2
3
4
5
6
7
8
#! /bin/bash

((a=1+2))
((b=$a+3))
echo $a
echo $b

exit 0

结果还是正确的

3
6

(())的用法与let完全相同

使用$[]

上面的效果需要这么写

1
2
a=$[1+2]
b=$[$a+3]

其余与上面两种限制大致相同

使用expr

关于这个方式是这么写的

1
2
a=`expr 1 + 2`
b=`expr $a \* 3`  #需要转义

需要额外注意的有:

  • 运算符两端需要加空格 一定要记住。。。很容易失误
  • 对于|、&、<、<=、>=、>、*运算符号需要加上\进行转义

使用bc

这个终于是可以用于浮点数的运算了

1
2
3
4
5
6
7
8
#! /bin/bash

a=3.1415926
b=`echo "$a*2"|bc`
echo $a
echo $b

exit 0

可以看到结果

3.1415926
6.2831852

据说这里还有一个scale来设置精度,但是我设置了感觉木有效果-_-

条件判断

if 语法

Shell脚本中有两种书写if判断的语法

  • 使用test 关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #! /bin/bash
    
    # if test expression1 operation expression2
    if test 5 -gt 4;  #这个最后的结尾可以加上:或者;
    then
        echo "ok,5>4"
    else
        echo "oh,no"
    fi #这个结束符号必须得加
    
    exit 0
    

    输出为

    ok,5>4
    
  • 使用[]关键字

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #! /bin/bash
    
    # if [ expression1 operation expression2 ]
    if [ 5 -lt 4 ];  #注意[和]两端必须留空格 同时表达式两端都需要有空格
    then
        echo "ok,5>4"
    else
        echo "oh,no"
    fi
    
    exit 0
    

    输出为

    oh,no
    

如果还更加复杂的判断你可以使用elif继续增加条件表达式,但是别忘了加then

判断表达式

Shell中有三种判断表达式

字符串比较

字符串比较 结果
string1 = string2 如果两个字符串相同,也可用==结果就为真
string1 != string2 如果两个字符串不同,结果就为真
-n string 如果字符串不为空,则结果为真
-z string 如果字符串为一个空串(null),则结果为真

这里需要注意下,-n 和 -z string比较时必须用双引号(“”)将变量引起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#! /bin/bash

a=5

if [ -n "$a"  ]  #注意要空括号来包住哦
then
    echo exists
else
    echo null
fi

if [ -n "$c"  ]
then
    echo exists
else
    echo null
fi

exit 0

结果为

exists
null

算术比较

算术比较 结果
expression1 -eq expression2 如果两个表达式相等,则结果为真
expression1 -ne expression2 如果两个表达式不等,则结果为真
expression1 -gt expression2 如果expression1 大于expression2 ,则为真
expression1 -ge expression2 如果expression1 大于等于expression2 ,则为真
expression1 -lt expression2 如果expression1 小于expression2 ,则为真
expression1 -le expression2 如果expression1 小于等于expression2 ,则为真
!expression 表达式为假,则结果就为真;反之亦然

关于上面比较符号的快速记法如下:eq=equal,gt=great than,lt=less than,然后组合拼凑即可,如果觉得这样还是很难记,就可以像我一样,将这些符号记录下来,需要的时候来查表-_-

 

文件条件测试

文件条件测试 结果
-d file 如果文件是一个目录,则为真
-f file 如果文件是一个普通文件,则为真;也可以用来测试文件是否存在
-r file 如果文件可读,则结果为真
-s file 如果文件大小不为0,则结果为真
-w file 如果文件可写,则结果为真
-x file 如果文件可执行,则结果为真

这,真的是一个利民的测试

循环结构

for 循环

先来看一种经典C语法版的for

1
2
3
4
5
6
7
#! /bin/bash

for ((i=0;i<5;i++))
do
    echo $i
done
exit 0

看输出,

0
1
2
3
4

还支持在外部控制步长

1
2
3
4
5
6
7
8
#! /bin/bash

for ((i=0;i<5;))
do
    echo $i
    i=$[$i+2]
done
exit 0
0
2
4

是不是感觉基本功能都有呀,就是写某些东西写起来奇怪点
是不是有一种莫名的熟悉感

另一种就是类似foreach的情况了,他的格式是这样的

1
2
3
4
for variable in values
do
    statements
done

其中values 可能有的情况为:

  1. 使用linux命令输出的行作为迭代的输入:ls,seq,cat之类均可,其实就可以完成很强大的文件读取功能

    1
    2
    3
    4
    5
    6
    7
    
    #! /bin/bash
    
    for i in `head -n 5 words.dit`;do  #words.dit 这是一个通用词表 每行一个词
        echo $i
    done
    
    exit 0
    

    可以看到通用词典中前5个词

    阿
    阿巴丹
    阿巴岛
    阿巴鸟
    阿巴伊达
    
  2. 使用$*可以来表示遍历传入的参数列表

    1
    2
    3
    4
    5
    6
    7
    
    #! /bin/bash
    
    for i in $*;do
        echo $i
    done
    
    exit 0
    

    来看个结果

    yans-MacBook-Pro:Downloads yanyl$ ./hi.sh  my name is tom
    my
    name
    is
    tom
    
  3. 还可以使用带空格的字符串 来进行按空格分隔输出

    1
    2
    3
    4
    5
    6
    7
    8
    
    #! /bin/bash
    
    a="yello red green"
    for i in $a;do
        echo $i
    done
    
    exit 0
    

    这样在一定程度上可以看成一个简易的数组

这里需要注意的是包含条件以及循环逻辑是双重括号,以及开始结果的doDone

while 循环

另一个常用的就是while循环了

他的结构是

1
2
3
4
while condition
do
    statements
done

这个也是蛮好理解的,可以来看一个demo

1
2
3
4
5
6
7
8
9
10
11
12
13
#! /bin/bash

echo "please ent your password:"
read pwd

while [ "$pwd"x != "root"x  ] #这里加x是为了防止啥也不输入直接回车产生的报错
do
    echo "error,please try again:"
    read pwd
done
echo "welcome here"

exit 0

看一下结果

please ent your password:
sha
error,please try again:

error,please try again:
root
welcome here

很有意思的一个哈~

until语句

这个语句与while的结构完全一样,只是使用了until关键字来代替了while,然后在条件为true的时候停止,正好与while相反

函数

Shell这么叼,能没有函数吗

1
2
3
4
[function] functon_name()
{
    statements
}

上面是定义函数的结构,大致有以下几个要点

  1. 前面的function关键字可有可无,不过感觉还是加上去比较好,这样在代码里面比较好辨识
  2. 函数名后面的括号中不能带参数 取的参数是用过$1,$2…$n这样的方式来取的
  3. 调用的时候直接写函数名 不需要加括号
  4. 如果想传递参数的话 直接在调用后来加上参数列表 用空格隔开 (就是Shell的传参一样)
  5. 使用local关键字来定义函数体里面的局部变量
  6. 所以在函数调用必须在函数定义之后

先看一个小的demo

1
2
3
4
5
6
7
8
9
10
#! /bin/bash

function sayhi()
{
    echo hi $1
}

sayhi tom #前面的sayhi是函数的调用 后面的tom是传参

exit 0

可以看到输出

hi tom

函数的返回值

关于Shell的返回值方式有两种

  1. 输出给主程序,他的结构为:

    1
    2
    3
    4
    5
    6
    
    function function_name()
    {
    	echo $something  #通过输出的方式来返回值
    }
    
    a=`function_name`  这种方式接收返回值
    

    看到的demo可以是这样的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    Press ENTER or type command to continue
    #! /bin/bash
    
    function sum()
    {
        echo $[$1+$2]
    }
    
    a=`sum 1 2`
    
    echo the sum is $a
    exit 0
    

    最终输出结果为

    the sum is 3
    
  2. 使用return作为返回码来返回值

    1
    2
    3
    4
    5
    6
    7
    
    function function_name()
    {
    	return $ret #这里进行返回码的返回
    }
    
    function_name
    $? #在这里接收返回值
    

    一样再来一个demo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #! /bin/bash
    
    function sum()
    {
        return $[$1+$2]
    }
    
    sum 1 2
    echo the sum is $?
    
    exit 0
    

    可以看到输出为

    the sum is 3
    

case语句

这里的case的与传统的switch有点像,但是又像scala中的match模式匹配的强大,

他的结构是这样的

1
2
3
4
5
case variable in
    pattern [ | pattern] ...) statements;;
    pattern [ | pattern] ...) statements;;
    ...
esac

来看这个强大的demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#! /bin/bash

function match()
{
    case $1 in
        root ) echo this is password ;;
        h* ) echo hi $1 ;; #使用通配符
        yes | YES ) echo agree with me ;; #可以进行或操作
        * ) echo everything is here;;  #你可以理解为switch中的default
    esac
}

match root
match hello
match YES
match Yes
exit 0

来看一下结果

this is password
hi hello
agree with me
everything is here

注意,这里一旦匹配中了一个之后就马上会停止匹配

外部命令/文件/语言的调用

Shell的另一个强大之处就是可以无缝的和外部的命令,文件,语言结合,去调用组织他们

  1. 外部命令:一般情况下可以直接写外部命令,如果要赋值的话得使用``括起来
  2. 外部文件:比如资源配置文件,profile文件之类的,可以直接使用source关键字的来执行
  3. 外部语言:比如java,python可以直接使用他们的java调用jar,java文件,也可以直接使用关键字来执行python文件

总结

  1. Shell很好很强大,得学习!!!
  2. 注意变量的字符串格式以及需要数学运算时的语法
  3. 注意变量赋值时等号两端一定不能有空格以及再取值时一定要加$
  4. 平常的控制结束符号别忘了,比如fi,doen,esac
  5. 忘了的时候来查查这个文件

 

原文:http://kubicode.me/2015/11/04/Linux/Shell-Command-List/

上一篇:

下一篇:

相关推荐

网站地图|XML地图

Copyright © 2015-2024 技术拉近你我! All rights reserved.
闽ICP备15015576号-1 版权所有©psz.