shell的学习

shell的学习

一.简述shell:

shell在官方的定义是linux内核的外壳,提供外部与Linux内核之间交互的工具。shell是一种语言,具有跨平台移植性,有多个版本如csh,ksh,sh。个人用的最多的是bash,Linux 操作系统缺省的 shell 是Bourne Again shell,它是 Bourne shell 的扩展,简称 Bash。

查看当前使用的shell类别:

[email protected]-unknown85879:/home/zhugeling$ which sh
/bin/sh
[email protected]-unknown85879:/home/zhugeling$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Nov 13 12:01 /bin/sh -> bash

二、如何学习shell?

个人感悟:其实shell的语法跟C语言差不多,但是shell还有很多可供使用的很多强大的命令,如sed,awk,grep等,实用性更强。在学习过程中,基础语法并不是很多,但是结合正则表达是和各种命令之后,变得很灵活。个人的感觉是在理解shell的解析原理基础上要多练习,多练习,多练习!!!不然记不住那么多命令,参数等等。

三、学习shell基础语法

1、变量:

(1)shell的变量不需要特殊声明,引用的时候要在前面用$符号。

(2)变量的赋值,对空格比较敏感,如:

 [[email protected] ~]# myvalue= 123
-bash: 123: command not found
[[email protected] ~]# myvalue =123
-bash: myvalue: command not found
[[email protected] ~]# myvalue=123
[[email protected] ~]# echo $myvalue
123

变量赋值时,”=”号两边不能有空格

另外引用变量时,尽量用{} 确定变量的范围,变量名不能含有内置变量(shell的特殊变量)。

双引号和单引号对变量的影响 
单引号里用$引用的变量将失效:

[email protected]-unknown85879:~/tmp$ name=zhugeling
[email protected]-unknown85879:~/tmp$ echo $name
zhugeling
[email protected]-unknown85879:~/tmp$ sayhello="Hello $name"
[email protected]-unknown85879:~/tmp$ echo $sayhello
Hello zhugeling
[email protected]-unknown85879:~/tmp$ sayhello=‘Hello $name‘
[email protected]-unknown85879:~/tmp$ echo $sayhello
Hello $name

(3)shell的特殊变量: 
shell有一些特殊变量,这些变量经常在脚本用回用到,有必要学会如何使用。

$0      当前脚本的文件名
$n      传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$#      传递给脚本或函数的参数个数。
$*      传递给脚本或函数的所有参数。
[email protected]      传递给脚本或函数的所有参数。被双引号(" ")包含时,与 $* 稍有不同,下面将会用测试用例讲到。
$?      上个命令的退出状态,或函数的返回值。一般情况下,大部分命令执行成功会返回 0,失败返回 1。
$$      当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。

测试变量: 
测试示例1:输出各个内置变量的含义值

[[email protected] tmp]# cat test.sh
#!/bin/bash
a=$0
b=$2
c=$#
d=$*
e=[email protected]
f=$?
g=$$
echo $a
echo $b
echo $c
echo $d
echo $e
echo $f
echo $g

输入1,2,3参数,输出:

[[email protected] tmp]# sh test.sh 1 2 3
test.sh
2
3
1 2 3
1 2 3
0
26583

测试示例2:研究?和@的区别

[email protected]-unknown85880:~/tmp$ cat test.sh
#!/bin/bash

for var in "$*"
do
    echo "* is $var"
done

for var in "[email protected]"
do
    echo "@ is $var"
done

[email protected]-unknown85880:~/tmp$ sh test.sh 1 3 5 6
* is 1 3 5 6
@ is 1
@ is 3
@ is 5
@ is 6

区别:?在同一行了,而@则逐个换行了,怀疑是 $* 把所有参数当成一个变量了,我们修改脚本测试一下,加入自加变量并输出。

[email protected]-unknown85880:~/tmp$  cat test.sh
#!/bin/bash
i=0
j=0
for var in "$*"
do
    echo "* is $var"
    i=$((i+1))
    echo "i is $i"
done

for var in "[email protected]"
do
    j=$((j+1))
    echo "j is $j"
    echo "@ is $var"
done
[email protected]-unknown85880:~/tmp$ sh test.sh 1 3 5 6
* is 1 3 5 6
i is 1
j is 1
@ is 1
j is 2
@ is 3
j is 3
@ is 5
j is 4
@ is

可以确认他们的区别就是,当引用@和* 的使用,如果用双引号扩起来,则?是会变成一个变量值,而@则是会按空格区分多个变量,如果输入的参数 类似 “a d”,也会被当成一个变量。

(4)获取用户输入为变量赋值:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
echo -e "input your name:"
read name
echo "your name is $name !"

[email protected]-unknown85879:~$ sh test.sh
input your name:
zhugeling
your name is zhugeling !

2、数组:

shell也是一种语言,数组也是必不可少的,数组也是一种变量,组合变量。

shell的数组下标是用中括号括起来,从0开始计算第一个数组变量,声明时可以直接赋给值,用空格分隔开变量值。

数组使用示例:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
#空数组arr1
arr1=() 

arr2=(1 2 3 4 5 6)
echo ${arr2[0]}
echo ${arr2[5]}

[email protected]-unknown85879:~$ sh test.sh
1
6

数组可以参与循环的使用:

for循环引用数组的时候,数组的下标用@符号,其含义可以参看前面的特殊变量说明,将@换成*也可以实现下面的效果。

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
#空数组arr1
arr1=() 

arr2=(1 2 3 4 5 6)

for var in ${arr2[@]}
do
  echo "i am $var !"

done

[email protected]-unknown85879:~$ sh test.sh
i am 1 !
i am 2 !
i am 3 !
i am 4 !
i am 5 !
i am 6 !

3、if判断语句:

算术比较运算符
num1 -eq num2              等于         [ 3 -eq $mynum ]
num1 -ne num2              不等于       [ 3 -ne $mynum ]
num1 -lt num2                小于        [ 3 -lt $mynum ]
num1 -le num2               小于或等于     [ 3 -le $mynum ]
num1 -gt num2               大于          [ 3 -gt $mynum ]
num1 -ge num2              大于或等于    [ 3 -ge $mynum ]
[  -z  " $num" ]               等于零
     =                           两个字符相等
  !=                两个字符不等
  -n    非空串  不为空
  –b 当file存在并且是块文件时返回真
  -c 当file存在并且是字符文件时返回真
  -d 当pathname存在并且是一个目录时返回真
  -e 当pathname指定的文件或目录存在时返回真
  -f 当file存在并且是正规文件时返回真
  -g 当由pathname指定的文件或目录存在并且设置了SGID位时返回为真
  -h 当file存在并且是符号链接文件时返回真,该选项在一些老系统上无效
  -k 当由pathname指定的文件或目录存在并且设置了“粘滞”位时返回真
  -p 当file存在并且是命令管道时返回为真
  -r 当由pathname指定的文件或目录存在并且可读时返回为真
  -s 当file存在文件大小大于0时返回真
  -u 当由pathname指定的文件或目录存在并且设置了SUID位时返回真
  -x 当由pathname指定的文件或目录存在并且可执行时返回真。一个目录为了它的内容被访问必然是可执行的。
  -o 当由pathname指定的文件或目录存在并且被子当前进程的有效用户ID所指定的用户拥有时返回真

语法: 
(1)单分支:

if 判断条件;then
    .......
fi
(2)双分支:
if 判断条件;then
    .....
    else
    ....
fi

(3)多分支会用到elif: 注意elif 也要带 then 
例如:

if [[ "$x" -le "100" ]];then
    echo "good."
elif [[ "$x" -lt "60" ]];then
    echo "ok."
else
    echo "Unknow argument...."
fi

常见用法: 
(1)判断脚本程序中前一句的执行情况: 
$? 为0则是执行成功,1则失败

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
cd  /home/zhugeling
if [ $? -eq 0 ];then
    echo "success"

else
    echo "fail"
fi

[email protected]-unknown85879:~$ sh test.sh
success

(2)、判断用户输入的参数是否为空:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "input your name:" name
if [ ! -n "$name" ] ;then
   echo "your input is null !"
else
   echo "your input is $name"
fi

[email protected]-unknown85879:~$ sh test.sh
input your name:zhugeling
your input is zhugeling
[email protected]-unknown85879:~$ sh test.sh
input your name:
your input is null !

(3)、判断文件夹是否存在,判断文件是否存在:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "input your file :" file

if [ -d "$file" ]
then
     echo "diretory $file found."
 else
      echo "diretory $file not found."
fi

if [ -f "$file" ]
then
    echo "file $file found."
else
    echo "file  $file not found."
fi

[email protected]-unknown85879:~$ sh test.sh
input your file :tmp
diretory tmp found.
file  tmp not found.
[email protected]-unknown85879:~$ sh test.sh
input your file :test.sh
diretory test.sh not found.
file test.sh found.

(4)判断字符串或数值等于,大于,小于等:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "input your number1 :" number1
read -p "input your number2 :" number2

if [ $number1 -eq $number2 ]
then
     echo "$number1 等于  $number2."
elif [ $number1 -gt $number2 ]
then
     echo "$number1 大于 $number2 "

else
     echo "$number1 小于 $number2 "
fi

[email protected]-unknown85879:~$ sh test.sh
input your number1 :12
input your number2 :13
12 小于 13
[email protected]-unknown85879:~$ sh test.sh
input your number1 :18
input your number2 :16
18 大于 16
[email protected]-unknown85879:~$ sh test.sh
input your number1 :12
input your number2 :12
12 等于  12.

上面判断的变量值还可以是字符串,用于字符串是否与预期的一致等。 
判断字符串是否相等 不能用 -eq 要用: = 或 ==号:

if [ “var"="var2“ ] ;then 
…. 
fi

4、shell的循环

(1)for循环

语法格式:

格式1:

  for 变量 in 列表值1 列表值2 ... 列表n值
do
    语句1
    语句2
    ...
    语句n
done

示例:看看下面两种循环条件的写法,保证 in后面的是一组有值的变量或常量。

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "input your number1 :" number1
read -p "input your number2 :" number2
for var in $(seq $number1 $number2)
do
  echo "now is $var"

done

for var in {1..3}
do
  echo "now $var"
done

[email protected]-unknown85879:~$ sh test.sh
input your number1 :1
input your number2 :4
now is 1
now is 2
now is 3
now is 4
now 1
now 2
now 3

格式2:类似C语言格式

for ((初始值;判断条件;步长值))
do
    语句1
    语句2
    ...
    语句n
done

示例:

#!/bin/bash
read -p "input your number1 :" number1
read -p "input your number2 :" number2
for((i=$number1;i<$number2;i++))
do
  echo "now is $i"

done

[email protected]-unknown85879:~$ sh test.sh
input your number1 :1
input your number2 :3
now is 1
now is 2

(2)、while循环

格式1:
        while [ $num  -le $num2 ]    ------两个变量之间
    do
        语句1
        语句2
        ...
        语句n
        num =$((num+1))         ----------变量自加方式1
    done

格式2:

    while [ $num  -le $num2 ]    ------两个变量之间
    do
        语句1
        语句2
        ...
        语句n
         num=` expr  $num +  1`     ---变量自加方式2
    done

示例:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "input your number1 :" number1
read -p "input your number2 :" number2
i=$number1
#while [ $i -le $number2 ]
while (($i<$number2))
do
  echo "now is $i"
  i=$(($i+1))

done

[email protected]-unknown85879:~$ sh test.sh
input your number1 :1
input your number2 :3
now is 1
now is 2

(3)、循环的常见用处:

按文件列表循环:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
read -p "inputh your dir:" dir
for var in `ls  $dir`
do
  echo "file is $var"
done

[email protected]-unknown85879:~$ sh test.sh
inputh your dir:/home/zhugeling/tmp
file is test1.txt
file is test2.txt
file is test3.txt

批量创建用户或文件(这里以创建文件示例):

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
dir=/home/zhugeling/tmp
cd  $dir
for var in {1..10}
do
   touch filename$var
done

[email protected]-unknown85879:~$ sh test.sh
[email protected]-unknown85879:~$ cd tmp/
[email protected]-unknown85879:~/tmp$ ls
filename1  filename10  filename2  filename3  filename4  filename5  filename6  filename7  filename8  filename9

循环检测一个IP段的连通性:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash

for var in {1..20}
do
   ping -c2 10.83.3.$var &>/dev/null
   if [ $? -eq 0 ];then
       echo "10.83.3.$var is exist !"
   else
       echo "10.83.3.$var is not exist !"
   fi
done

 [email protected]-unknown85879:~$ sh test.sh
10.83.3.1 is exist !
10.83.3.2 is not exist !
10.83.3.3 is not exist !
10.83.3.4 is not exist !
10.83.3.5 is not exist !
10.83.3.6 is not exist !
10.83.3.7 is not exist !
10.83.3.8 is not exist !
10.83.3.9 is not exist !
10.83.3.10 is exist !
10.83.3.11 is exist !
10.83.3.12 is exist !
10.83.3.13 is exist !
10.83.3.14 is exist !
10.83.3.15 is exist !
10.83.3.16 is exist !
10.83.3.17 is exist !
10.83.3.18 is exist !
10.83.3.19 is exist !
10.83.3.20 is exist !

此外循环还可以用于统计数值,循环执行某些命令等用途。

5、shell的分支case

shell的分支是用case语句控制,语法如下:

case 值 in
模式1)
     命令1
     ...
     ;;
模式2)
     命令2
     ...
     ;;
......
esac

简单示例:

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash
case $1 in
    start )
        echo "server is starting !"
        ;;
    stop )
        echo "server is stopping !"
        ;;
    restart)
        echo "server is restarting !"
        ;;
    *)
        echo "you input is error,please try again!"
        ;;
esac

[email protected]-unknown85879:~$ sh test.sh stop
server is stopping !
[email protected]-unknown85879:~$ sh test.sh
you input is error,please try again!
[email protected]-unknown85879:~$ sh test.sh start
server is starting !

加参数选项的示例:

#!/bin/bash
while getopts :b:d: OPT &> /dev/null;
do
    case $OPT in
    b)
        echo "is b"
        echo $OPTARG
        ;;
    d)
        echo "is d"
        echo $OPTARG
        ;;
    *)
        echo "error "
        exit 7
        ;;
    esac
done

[email protected]-unknown85879:~$ sh getopt.sh -d dd
is d
dd
[email protected]-unknown85879:~$ sh getopt.sh -b hello
is b
hello

6、shell的函数

几乎所有语言都会有函数,shell也不例外,下面看看函数的语法:

格式: 
function functionname () 

body; 
}

调用方式:直接函数名调用

functionname

示例1:我将之前的用于case语句的实例,改写成用函数实现看看

[email protected]-unknown85879:~$ cat test.sh
#!/bin/bash

function stop ()
{
   echo "your chiose is stop ,stopping !"
}

function start ()
{
  echo "your chiose is start,startting !"
}

function restart ()
{
      echo "your chiose is restart,restartting !"
}

if [ "$1" = "stop" ];then
    stop
elif [ "$1" = "start" ];then
    start
elif [ "$1" = "restart" ];then
    restart
else
    echo "your input is error ,try again !"
fi

[email protected]-unknown85879:~$ sh test.sh
your input is error ,try again !
[email protected]-unknown85879:~$ sh test.sh stop
your chiose is stop ,stopping !
[email protected]-unknown85879:~$ sh test.sh start
your chiose is start,startting !
[email protected]-unknown85879:~$ sh test.sh restart
your chiose is restart,restartting !
[email protected]-unknown85879:~$ 

这里注意对比字符串时,if里面的变量要双引号括起来,否则会报错,== 和 =在这里是等价的。

四、shell的环境变量

1、环境变量有哪些,如何保存和生效?

(1)环境变量有很多,按不同的作用域分有系统环境变量如path,用户环境变量如用户自定义的家目录,或者命令别名,应用环境变量如jdk环境变量。 
如何查看:直接输入 env 
查看某个环境变量:如查看path: echo $PATH

(2)按作用时间来看有临时环境变量,有永久环境变量: 
比如我们的$HOME是一个永久环境变量,我们要临时修改它,直接export 一下:

[email protected]-unknown85879:~$ echo $HOME  ---修改前
/home/zhugeling
[email protected]-unknown85879:~$ export HOME=‘/home/tmp‘
[email protected]-unknown85879:/home/zhugeling$
[email protected]-unknown85879:/home/zhugeling$ echo $HOME  ---修改后
/home/tmp

说明这种事临时生效,系统重启,或重新打开一个shell终端是会失效的。 
环境变量永久生效的办法:直接修改配置文件或将修改保存到配置文件

(3)、常见环境变量的配置文件有哪些? 
系统全局作用: 
/etc/profile 
/etc/profile.d/*.sh 
/etc/bashrc 
生效: source 路径

对当前用户起作用: 
~/.bash_profile 
~/..bashrc 
生效: source 路径

对应用本身起作用的(不同应用配置文件名和路径不一样): 
/etc/ssh/sshd_config 
/etc/ssh/ssh_config

生效:一般是重启应用或reload

2、shell的ps1/ps2/ps3有什么用:

(1)ps1: 
先来个例子看看是什么作用的

[email protected]-unknown85880:~/tmp$ export PS1=‘\t >‘
20:24:06 >
20:24:07 >

说明:从上例可以看到ps1可以通过export方式改变系统的终端提示符,ps1就是命令行提示符的环境变量。上面通过export改变环境变量的值,将显示结果改成时间而达到的效果。它还有更多其他参数如:

\a搜索  显示系统日期,格式:星期 日期
  例:PS1="\d >" 结果:六 10月 24 >
\A  显示系统时间,格式:HH:MM
  例:PS1="\A >" 结果:21:04 >
\t  显示系统时间,格式:HH:MM:SS (24小时制)
  例:PS1="\t >" 结果:21:04:32 >
\T  显示系统时间,格式:HH:MM:SS (12小时制)
  例:PS1="\T >" 结果:09:04:32 >
\h  显示主机名称(简称)
  例:PS1="\h >" 结果:CentOS >
\H  显示主机名称(全称)

默认值是:[\[email protected]\h \W]$ 
刚刚只是临时修改,如果要长久生效怎么办? 
放在个人家目录下的 .bashrc吧 
如: 
export PS1=’\t\h’

如果要全局生效呢? 
我们来试试,我修改了/etc/profile的文件,后面追加 export PS1=’\t\h’,source之后,root用户立马生效,但是登录其他用户发现没效果。

排查发现用户下的.bashrc是有对PS1设置的:

if [ "$color_prompt" = yes ]; then
    PS1=‘${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\[email protected]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ‘
else
    PS1=‘${debian_chroot:+($debian_chroot)}\[email protected]\h:\w\$ ‘
fi
unset color_prompt force_color_prompt

经查资料,原来是登录读取配置文件的先后顺序也有关,最后读取的当然是最终起作用了:

/etc/profile ->.bash_profile -> .bashrc -> /etc/bashrc

那我们改 /etc/bashrc 试试:

[email protected]-unknown85880:~# source /etc/bash.bashrc
20:49:05newbie-unknown85880:
20:49:06newbie-unknown85880:
20:49:06newbie-unknown85880:
20:49:06newbie-unknown85880:tail -1 /etc/bash.bashrc
export PS1=‘\t\h:‘

果然如此。

Shell还有PS2,PS3,ps2是Shell的次提示符,PS3是Shell脚本中使用select时的提示符

举例: 
默认显示如下:



[email protected]-unknown85881:~$ sh test.sh
1) mon
2) tue
3) wed
4) exit
#? 1
Monday
#? 2
Tuesday
#? 3
Wednesday
#? ^C

修改PS3=’\tmyshell’:

[email protected]-unknown85881:~$ export PS3=‘\tmysell:‘
[email protected]-unknown85881:~$ sh test.sh
1) mon
2) tue
3) wed
4) exit
\tmysell:1
Monday
\tmysell:2
Tuesday
\tmysell:

其他的生效顺序,长久生效配置跟ps1是一样的。

3、登录方式不一样对环境变量的影响:

有时候我们会碰到,用不同的用户去启动一个应用时会报错,除了文件权限不一样之外,通常还有另外一个原因就是不同用户的环境便令不一样。 
(1)登录shell和非登shel: 
登录shell:是通过账号密码登录进入shell的(或者通过”–login”选项生成的shel) 
非登录shell:不需要账号密码,直接通过bash命令或者桌面右键打开的终端。

[email protected]-unknown85879:/etc/ssh# echo $$
26497
[email protected]-unknown85879:/etc/ssh# bash
[email protected]-unknown85879:/etc/ssh# echo $$   ---shell的进程ID跟之前不一样
30154
[email protected]-unknown85879:/etc/ssh# exit
exit

正常登录文件的读取调用关系: 
执行/etc/profile中的命令,然后/etc/profile调用/etc/profile.d目录下的所有脚本;然后执行~/.bash_profile,~/.bash_profile调用~/.bashrc,最后~/.bashrc又调用/etc/bashrc

非登录shell: 
执行~/.bashrc,~/.bashrc调用/etc/bashrc,然后调用/etc/profile.d/*下的所有脚本。

区别:非登录shell不会重新加载/etc/profile,而且顺序也不一样,如果你的环境变量设置是在/etc/profile和~/.bash_profile ,建议重新登录或source一下对应的配置文件。

登录方式:su user 和 su - user的区别: 
su user :只是切换了用户,切换了权限,但是环境变量没变。 
su - user : 切换了用户,切换了权限,也切换了环境变量

[email protected]-unknown85879:/home/zhugeling$ su root
Password:
[email protected]-unknown85879:/home/zhugeling#   ---目录没换

[email protected]-unknown85879:/home/zhugeling$ su - root
Password:
[email protected]-unknown85879:~#   ---目录换了

(2)交互式shell和非交互式shell: 
我们把命令行终端这种输入一个命令,shell、去执行,然后输出结果,这种叫交互式shell,非交互式shell是指shell自己一直执行到执行完就退出shell的模式,脚本执行就是典型的非交互式shell。 
我们可以通过echo $- 来判断当前是什么类型的shell:

[email protected]-unknown85879:/etc/ssh# echo $-  --交互式
himBHs
[email protected]-unknown85879:/etc/ssh# cat test.sh
echo $-
[email protected]-unknown85879:/etc/ssh# sh test.sh ---非交互式
hB

在环境变量上的区别: 
交互式shell:就是当前登录用户的环境变量(根据登录方式不同也会有区别) 
非交互式shell:继承当前登录用户的环境变量,在此基础上shell可以在脚本里加载其他环境变量,如通过export PATH=’..’ 等

五、正则表达式和通配符的区别

(1)、作用对象和范围不一样:

作用对象: 
通配符用于Linux的shell命令(如文件名相关操作),如常结合find ,cp,mv等命令使用 
正字表达是是用于文本字符串或者标准输出里的内容的过滤和匹配 
作用范围: 
通配符必须在unix环境或类Unix环境中使用 
正则表达式在很多语言中都支持,是一种标准,可以写在代码中,跨平台性好。

(2)解释器不一样:

通配符是Linux系统本身支持的,由shell去解析执行。 
正则表达式在使用过程中有可能是shell去解析,也有可能是awk,perl等支持正则的命令去解析,就看使用方式是怎么用。 
如:

[email protected]-unknown85879:/home/zhugeling$ ls -l logrotate.sh_* |grep "*"   ---这里前面*号是通配符,后面*号只是一个*号
-rw-r--r-- 1 zhugeling zhugeling 1628 Feb  1 12:13 logrotate.sh_v*
[email protected]-unknown85879:/home/zhugeling$ ls -l logrotate.sh_*    ---这里*号是通配符号
-rw-r--r-- 1 zhugeling zhugeling 1628 Feb  1 12:13 logrotate.sh_v*
-rw-r--r-- 1 zhugeling zhugeling  969 Jan 30 20:34 logrotate.sh_v1
-rw-r--r-- 1 zhugeling zhugeling 1940 Jan 31 11:20 logrotate.sh_v2
-rw-r--r-- 1 zhugeling zhugeling 1628 Jan 31 12:11 logrotate.sh_v3
[email protected]-unknown85879:/home/zhugeling$ ls -l logrotate.sh_* |grep ‘v*‘  --这里*号是正则修饰符
-rw-r--r-- 1 zhugeling zhugeling 1628 Feb  1 12:13 logrotate.sh_v*
-rw-r--r-- 1 zhugeling zhugeling  969 Jan 30 20:34 logrotate.sh_v1
-rw-r--r-- 1 zhugeling zhugeling 1940 Jan 31 11:20 logrotate.sh_v2
-rw-r--r-- 1 zhugeling zhugeling 1628 Jan 31 12:11 logrotate.sh_v3

ls -l logrotate.sh_* |grep ‘v*’ 中 起一个是由shell去解释执行的,而后面的是由grep 解释的,发现grep 后面用星号作为正则修饰符的话,记得前面不能为空,否则就不是正则里的修饰符作用了。

(3)符号用法含义不一样:

正则表达式支持的功能比较多,且符号的作用含义跟通配符很多是不一样的,比如:

$符号: 
正则表示字符串的结尾 
通配符中经常用来来引用变量。

*符号 
正则里是修饰符,表示0个或多个,不能单独使用,例如 a* 表示0个a或者多个a。 
通配符里表示的是任意字符,任意个,即匹配所有。

. 符号 
正则里是匹配任意单个字符 
通配符里没有这个含义,通配符用?来实现匹配任意单个字符的功能

[email protected]-unknown85879:/home/zhugeling$ find ./ -name "logrotate.sh_v?"
./logrotate.sh_v*
./logrotate.sh_v1
./logrotate.sh_v2
./logrotate.sh_v3

六、管道与重定向

(1)标准输入输出:

了解重定向首先要了解标准的输入输出是什么:

0: Standard Input (STDIN) 标准输入,如键盘输入

1: Standard Output (STDOUT) 标准输出,正确返回值,输出到前端

2: Standard Error Output (STDERR) 错误输出,输出到前端

(2)重定向

重定向就是将标准的输入或者输出重新指向到指定的文件或其他管道中。 
“>” 重定向覆盖或新生成文件 
如:1>文件名 可以将1省略,写成 >文件名

echo "hello" >test.txt
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.txt
hello

“>>” 重定向追加到指定文件中

echo "hellohhhh" >>test.txt
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.txt
hello
hellohhhh

错误输出重定向:

[email protected]-unknown85879:/home/zhugeling/tmp$ ppspsp 2>test.txt
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.txt
-bash: ppspsp: command not found

看下下面两个有什么区别:

pdkf 1>> test.txt 2>&1 将错误输出也输出到1标准输出通道中,继而输出到文件,是追加方式。 
pdkf 1> test.txt 2>>&1 这种是错误的写法

cat test2.txt和cat> test2.txt的区别:

[email protected]-unknown85879:/home/zhugeling/tmp$ cat >test2.txt
lll
lsld
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test2.txt
lll
lsld

输入重定向: 
cat> test.txt<输出给test.txt 
第一个EOF必须以重定向字符<<开始,第二个EOF必须顶格写,否则会报错

[email protected]-unknown85879:/home/zhugeling/tmp$ cat> test.txt<<eof
> haohsd
> aldwe
> eof
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.txt
haohsd
aldwe

(3)、管道命令:

-exec 使用时最后面一定要加;号表示结束,一般用反斜杠将;转义。

[email protected]-unknown85879:/home/zhugeling/tmp$ find ./ -name "test*"
./test.txt
./test2.txt
[email protected]-unknown85879:/home/zhugeling/tmp$ find ./ -name "test*" -exec cp {} /home/zhugeling/tmp/log/ \;
[email protected]-unknown85879:/home/zhugeling/tmp$ cd log/
[email protected]-unknown85879:/home/zhugeling/tmp/log$ ls test*
test2.txt  test.txt

exec有个特点要注意:exec后面跟的是其他命令,当其他命令执行完之后,会退出当前shell,后面语句不执行,我在脚本测试是这样,命令行终端没测明白。

[email protected]-unknown85879:/home/zhugeling/tmp$ sh test.sh
hello mysql
 hello oracle
[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.sh
#!/bin/bash
echo "hello mysql"
exec echo " hello oracle"
echo "hello db2"

管道符号: | 
command 1 | command 2 他的功能是把第一个命令command 1执行的结果作为command 2的输入传给command 2

[email protected]-unknown85879:/home/zhugeling/tmp$ ls -s
total 8
4 log  0 test2.txt  4 test.sh

[email protected]-unknown85879:/home/zhugeling/tmp$ ls -s|sort -nr
4 test.sh
4 log
total 8
0 test2.txt

xargs 管道命令

xargs 可以读入 stdin 的资料,并且以空格或换行作为分隔,将 stdin 的内容分隔成为 arguments 。 因为是以空格作为分隔,所以,如果有一些内容或者是其他意义的名词内含有空格的时候, xargs 可能就会误判了,如果需要处理特殊字符,需要使用-0参数进行处理 
(1)、从文件中获取输入:

[email protected]-unknown85879:/home/zhugeling/tmp$ cat test.sh
#!/bin/bash
echo "hello mysql"
exec echo " hello oracle"
echo "hello db2"
[email protected]-unknown85879:/home/zhugeling/tmp$ xargs -a test.sh echo
#!/bin/bash echo hello mysql exec echo  hello oracle echo hello db2

(2)将find的结果通过xargs重定向输出给ls -l

[email protected]-unknown85879:/home/zhugeling/tmp$ find ./ -name "test*"
./test2.txt
./test.sh
[email protected]-unknown85879:/home/zhugeling/tmp$ find ./ -name "test*" |xargs ls -l
-rw-r--r-- 1 zhugeling zhugeling  0 Feb  1 14:36 ./test2.txt
-rwxr--r-- 1 zhugeling zhugeling 79 Feb  1 15:03 ./test.sh

七、bash与shell的区别

shell是Bourne shell 是 UNIX 最初使用的 shell,而Linux 操作系统缺省的 shell 是Bourne Again shell,它是 Bourne shell 的扩展,简称 Bash,与 Bourne shell 完全向后兼容,他们的区别我根据以下几点做了比较:

可移植性: 
bash的可移植性比shell要差一些,因为很多Linux版本都是在Unix上扩展出来的,那么其他shell也是在unix shell 上扩展出来的,扩展的shell一般都是向下兼容的。

功能使用: 
在编程方面,shell是做的不错的,但是不支持命令补全,命令编辑,命令历史表等功能,而bash 支持。

原文地址:https://www.cnblogs.com/lifei02/p/9892512.html

时间: 2024-10-07 20:22:27

shell的学习的相关文章

linux shell 命令学习(5) xxd- make a hexdump or do the reverse.

对于标准输入或者给定的文件,显示其16进制的内容.也可以反过来进行转换. ? 1 2 3 xxd -h[elp] xxd [options] [infile [outfile]] xxd -r[evert] [options] [infile [outfile]] 如果没有指定输入文件, 则采用标准输入. -b: 以2进制格式进行输出 ? 1 2 3 4 [[email protected] src]$ xxd -b train.ini 0000000: 01011011 01110100 01

笔记——shell脚本学习指南

<shell脚本学习指南>机械工业出版 ISBN 987-7-111-25504-8 第2章 2.4 初级陷阱 1.当今的系统,对#!这一行的长度限制从63到1024个字符都有,尽量不要超过64个字符. 2.在某些系统上,命令行部分包含了命令的完整路径名称.不过有些系统却不是这样:命令行的部分会原封不动地传递给被引用的程序. 3.别在选项之后放置任何空白,因为空白也会跟着选项一起传递给被引用的程序. 4.你需要知道解释其的完整路径名称.这可以用来规避可移植问题,因为不同的厂商可能将同样的东西放

shell脚本学习指南

以下八点不敢说就能成为你shell脚本学习指南de全部,至少可以让你编写出可靠的shell脚本. 1. 指定bash shell 脚本的第一行,#!之后应该是什么? 如果拿这个问题去问别人,不同的人的回答可能各不相同.我见过/usr/bin/env bash,也见过/bin/bash,还有/usr/bin/bash,还有/bin/sh,还有/usr/bin/env sh.这算是编程界的“’茴’字四种写法”了. 在多数情况下,以上五种写法都是等价的.但是,写过程序的人都知道:“少数情况”里往往隐藏

shell脚本学习与总结

shell脚本学习总结,东西很多,供初学者参考. shell脚本是区分大小写的. 2.Unix特殊字符有: ( ; $ ? & * () [] ` ' " + 使用其时要进行转义() 3.Shell的注释以#开头 4.函数的定义Function fuction_name(){ Command to execute} 调用时直接用function_name. 5.控制结构 1)If...then语句 If [ test_command ]    Then    Commandsfi2)If

shell脚本学习笔记系列--1

一.学好shell编程的知识储备 1.相关Linux系统命令应用: 2.Vi/vim 编辑器的熟练使用,相关客户端软件的设置: 3.基础的服务,系统服务ntp,crond,网络服务:nfs,rsync,inotify,sersync,ssh,lanmp等. 补充:清空日志的三种方法: 1)echo  " " > filename.log 2)>filename.log 3)cat  /dev/null > filename.log 注:工作中有的时候不能删除(日志)文

Linux shell 菜鸟学习笔记....

20171123 Linux shell 基础学习笔记1. shell 的开始 一般是 #!/bin/bash 通过 #! 来唯一指定使用的shell路径 其他的 # 都表示注释.2. shell 的变量 定义变量直接用 variablename= value 就可以 其中变量名与等号之间没有空格. 使用变量的时候 是 ${vairablename} 的方式进行使用 大括号可以有可以没有,但是建议有. 可以使用 for file in `ls /etc/` 的方式来循环取得文件名. 使用do d

shell脚本学习笔记:通过shell实现linux用户管理和监控

学习shell做的第一个脚本,感谢云知梦李强强老师的shell编程教程 创建shell脚本文件: touch menu.sh touch index.sh touch welcome.sh 赋予脚本文件可执行权限: chmod a+x menu.sh index.sh welcome.sh menu.sh #!/bin/bash #menu.sh function menu(){ title="My Home" name="Randy" time=`date +%Y

常见linux命令释义(第五天)——shell变量学习

由于时间有限,我写这篇博客的时间上限为30分钟.仅作为学习笔记而用,内容会尽量的讲清楚.如果讲的不清楚,你来打我啊! 玩笑开过,正式开始今天的学习. linux系统的中一些命令是在/bin下,这个是一般用户能够用的.还有一些是超级用户才能用的,这个命令放在/sbin下. 但还有一部分的命令就直接内置在bash内,随系统的启动直接读进内存的.这样能够最大的减少文件的索引时间,提高系统的效率. 可以通过 type 的命令来查看.type的意思是类型.可以形象的理解为照妖镜,看看你的本质来源到底是什么

Shell编程学习2--命令大全

Linux中有很多的命令,这些命令可分分为10类(具体参见[1]): 1) 文件管理; 2) 文档编辑; 3) 文件传输; 4) 磁盘管理; 5) 磁盘维护; 6) 网络通讯; 7) 系统管理; 8) 系统设置; 9) 备份压缩; 10) 设备管理. Linux: command1 | command2 "|"其实是Linux里面的一个管道符号, 将两个命令隔开, command1的输出作为command2的输入; 也可以连续使用多个管道, 表示command1的输出作为command