变量的定义

在定义变量时,有一些规则需要遵守:

 变量名称可以由字母、数字和下划线组成,但是不能以数字开头。如果变量名是“2name”则是错误的。

 在Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必修指定变量类型为数值型。

 变量用等号连接值,等号左右两侧不能有空格。

 变量的值如果有空格,需要使用单引号或双引号包括。如:“test="hello world!"”。其中双引号括起来的内容“$”、“\”和反引号都拥有特殊含义,而单引号括起来的内容都是普通字符。

    在变量的值中,可以使用“\”转义符。

    如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含"$变量名"或用${变量名}包含变量名。例如:

[kris@hadoop101 test]$ test=123
[kris@hadoop101 test]$ echo $test
123
[kris@hadoop101 test]$ test="$test"456
[kris@hadoop101 test]$ echo $test       #叠加变量test,变量值变成了123456
123456
[kris@hadoop101 test]$ test=${test}789  #再叠加变量test,变量值编程了123456789
[kris@hadoop101 test]$ echo $test     
123456789

变量值的叠加可以使用两种格式:"$变量名" 或${变量名}
 如果是把命令的结果作为变量值赋予变量,则需要使用反引号或$()包含命令。例如:
[kris@hadoop101 test]$ test=$(date)
[kris@hadoop101 test]$ echo $test
2021年 03月 28日 星期日 10:48:42 CST

环境变量名建议大写,便于区分。

变量的分类

① 用户自定义变量:这种变量是最常见的变量,由用户自由定义变量名和变量的值。

② 环境变量:这种变量中主要保存的是和系统操作环境相关的数据,比如当前登录用户,用户的家目录,命令的提示符等。不是太好理解吧,那么大家还记得在Windows中,同一台

电脑可以有多个用户登录,而且每个用户都可以定义自己的桌面样式和分辨率,这些其实就是Windows的操作环境,可以当做是Windows的环境变量来理解。环境变量的变量名可以

自由定义,但是一般对系统起作用的环境变量的变量名是系统预先设定好的。

③ 位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。

④ 预定义变量:是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。

① 用户自定义变量

变量的命名:

  #变量名不能用数字开头,#等号左右两侧不能有空格,#变量的值如果有空格,必须用引号包含

变量调用: 

  name="kris song"   #定义变量name

  echo $name          #输出变量name的值

变量查看:

  set   [选项]

选项:

  • -u: 如果设定此选项,调用未声明变量时会报错(默认无任何提示)
  • -x:   如果设定此选项,在命令执行之前,会把命令先输出一次

[kris@hadoop101 test]$ set

BASH=/bin/bash

…省略部分输出…

name='kris song'

#直接使用set命令,会查询系统中所有的变量,包含用户自定义变量和环境变量

[kris@hadoop101 test]$ set -u  #当设置了-u选项后,如果调用没有设定的变量会有报错。默认是没有任何输出的。
[kris@hadoop101 test]$ echo $file
-bash: file: unbound variable
[kris@hadoop101 test]$ set -x  #如果设定了-x选项,会在每个命令执行之前,先把命令输出一次
[kris@hadoop101 test]$ ls
+ ls --color=auto
012  0abc  abc  abcd

变量删除

[kris@hadoop101 test]$  unset 变量名

② 环境变量 

环境变量设置
  [kris@hadoop101 ~]$ export age="18"

环境变量查询和删除 

   env命令和set命令的区别是,set命令可以查看所有变量,而env命令只能查看环境变量。


[kris@hadoop101 ~]$ unset gender      #删除环境变量gender 
[kris@hadoop101 ~]$ env | grep gender
[kris@hadoop101 ~]$ env | grep age
  age=18

③系统默认环境变量

[kris@hadoop101 ~]$ env
HOSTNAME=hadoop101    #主机名
TERM=linux                    #终端环境
SHELL=/bin/bash           #当前的shell
HADOOP_HOME=/opt/module/hadoop-2.7.2
HISTSIZE=1000          #历史命令条数
SSH_CLIENT=192.168.1.1 9806 22  #当前操作环境是用ssh连接的,这里记录客户端ip
PHOENIX_CLASSPATH=/opt/module/phoenix
QTDIR=/usr/lib64/qt-3.3
QTINC=/usr/lib64/qt-3.3/include
SSH_TTY=/dev/pts/0   #ssh连接的终端时pts/1
PHOENIX_HOME=/opt/module/phoenix
USER=kris               #当前登录的用户
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:* #定义颜色显示
HBASE_HOME=/opt/module/hbase-1.3.1
age=18     #刚刚定义的环境变量
MAIL=/var/spool/mail/kris  #用户邮箱
PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/module/jdk1.8.0_144/bin:/opt/module/hadoop-2.7.2/bin:/opt/module/hadoop-2.7.2/sbin:/opt/module/hive/bin:/opt/module/hbase-1.3.1/bin:/opt/module/kylin/bin:/opt/module/phoenix/bin:/home/kris/bin      #系统查找命令的路径
HIVE_HOME=/opt/module/hive
PWD=/home/kris        #当前所在目录
JAVA_HOME=/opt/module/jdk1.8.0_144
LANG=zh_CN.UTF-8    #语系
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
HISTCONTROL=ignoredups
SHLVL=1                #当前在第一层子shell中。
HOME=/home/kris   #当前登录用户的家目录
KYLIN_HOME=/opt/module/kylin
LOGNAME=kris  #登录用户
QTLIB=/usr/lib64/qt-3.3/lib
CVS_RSH=ssh
SSH_CONNECTION=192.168.1.1 9806 192.168.1.101 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env   #上次执行命令的最后一个参数或命令本身

env命令可以查询到所有的环境变量,可是还有一些变量虽然不是环境变量,却是和Bash操作接口相关的变量,这些变量也对我们的Bash操作终端起到了重要的作用。

这些变量就只能用set命令来查看了

[kris@hadoop101 ~]$ set
BASH=/bin/bash       #Bash的位置
BASH_VERSINFO=([0]="4" [1]="1" [2]="2" [3]="1" [4]="release"
[5]="i386-redhat-linux-gnu")   #Bash版本
BASH_VERSION='4.1.2(1)-release' #bash的版本
COLORS=/etc/DIR_COLORS     #颜色记录文件
HISTFILE=/root/.bash_history   #历史命令保存文件
HISTFILESIZE=1000   #在文件当中记录的历史命令最大条数
HISTSIZE=1000     #在缓存中记录的历史命令最大条数
LANG=zh_CN.UTF-8   #语系环境
MACHTYPE=i386-redhat-linux-gnu #软件类型是i386兼容类型
MAILCHECK=60       #每60秒去扫描新邮件
PPID=2166 #父shell的PID。我们当前Shell是一个子shell
PS1='[\u@\h \W]\$ ' #命令提示符
PS2='> '     #如果命令一行没有输入完成,第二行命令的提示符
UID=0       #当前用户的UID

PATH变量:系统查找命令的路径

先查询下PATH环境变量的值:

[kris@hadoop101 ~]$ echo $PATH
/usr/lib64/qt-3.3/bin:
/usr/local/bin:
/bin:
/usr/bin:
/usr/local/sbin:
/usr/sbin:
/sbin:/opt/module/jdk1.8.0_144/bin:
/opt/module/hadoop-2.7.2/bin:
/opt/module/hadoop-2.7.2/sbin:
/opt/module/hive/bin:
/opt/module/hbase-1.3.1/bin:
/opt/module/kylin/bin:
/opt/module/phoenix/bin:
/home/kris/bin

PATH变量的值是用“:”分割的路径,这些路径就是系统查找命令的路径。也就是说当我们输入了一个程序名,如果没有写入路径,系统就会到PATH变量定义的路径中去寻找,是否有

可以执行的程序。如果找到则执行,否则会报“命令没有发现”的错误。

那么是不是我们把自己的脚本拷贝到PATH变量定义的路径中,我们自己写的脚本也可以不输入路径而直接运行呢?

那么我们是不是可以修改PATH变量的值,而不是把程序脚本复制到/bin/目录中。当然是可以的,我们通过变量的叠加就可以实现了:

[root@localhost ~]# PATH="$PATH":/root/sh
#在变量PATH的后面,加入/root/sh目录
[root@localhost ~]# echo $PATH
/usr/lib/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root/sh
#查询PATH的值,变量叠加生效了
当然我们这样定义的PATH变量只是临时生效,一旦重启或注销就会消失,如果想要永久生效,需要写入环境变量配置文件

位置参数变量

位置参数变量

作 用
$n n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}.
$* 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待
$# 这个变量代表命令行中所有参数的个数
#!/bin/bash
a=$1                #给a变量赋值是第一个参数
b=$2                #给b变量赋值是第二个参数
sum=$(( $a + $b ))  #变量sum的和是a+b
echo $sum           #打印变量sum的值
echo $0             #打印命令本身 
#!/bin/bash
echo "Total of $# parameters" #$#代表所有参数的个数
echo "The parameters is: $*"  #$*代表所有的参数
echo "The parameters is: $@"  #$@也代表所有参数
$*会把接收的所有参数当成一个整体对待,而$@则会区分对待接收到的所有参数,例如:
#
!/bin/bash #$* #定义for循环,in后面有几个值,for会循环多少次,注意“$*”要用双引号括起来 #每次循环会把in后面的值赋予变量i #Shell把$*中的所有参数看成是一个整体,所以这个for循环只会循环一次 for i in "$*" do echo "The parameters is: $i" #打印变量$i的值 done #$@ #同样in后面的有几个值,for循环几次,每次都把值赋予变量y #可是Shell中把“$@”中的每个参数都看成是独立的,所以“$@”中有几个参数,就会循环几次 x=1 #定义变量x的值为1 for y in "$@" do echo "The parameter$x is $y" #输出变量y的值 x=$(($x+1)) #变量x每次循环都加1,为了输出看的更清楚 done

预定义变量

预定义变量 作用
$?

最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;

如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。

$$ 当前进程的进程号(PID)
$! 后台运行的最后一个进程的进程号(PID)
[kris@hadoop101 ~]$ echo $? #预定义变量“$?”的值是0,证明上一个命令执行正确
0
[kris@hadoop101 ~]$ ls fill
ls: 无法访问fill: 没有那个文件或目录
[kris@hadoop101 ~]$ echo $?  #变量“$?”返回一个非0的值,证明上一个命令没有正确执行
#至于错误的返回值到底是多少,是在编写ls命令时定义好的,如果碰到文件不存在就返回数值2
2

#!/bin/bash
echo "The current process is $$"         #输出当前进程的PID,这个PID就是这个脚本执行时生产的进程的PID

find /home/kris -name count.sh &         #使用find命令在kris目录下查找count.sh文件   #符号&的意思是把命令放入后台执行
echo "The last one Daemon process is $!" #输出这个后台执行命令的进程的PID,也就是输出find命令的PID号

接收键盘输入

read [选项] [变量名]
选项:
  -p "提示信息":指定读取值时的提示符; -t 秒数:read会一直等待用户输入,使用此选项可以指定等待的时间(秒)。 -n 字符数: read命令只接受指定的字符数,就会执行。
-s: 隐藏输入的数据,适用于机密信息的输入。
#/bin/bash read -p "Please input a num in 5 seconds:" a echo $a


2. Shell的运算符

数值运算的方法

数值运算,可以采用以下三种方法中的任意一种:

1)使用declare声明变量类型

既然所有变量的默认类型是字符串型,那么只要我们把变量声明为整数型不就可以运算了吗?使用declare命令就可以实现声明变量的类型。命令如下:

declare [+/-][选项] 变量名
选项:
-: 给变量设定类型属性
+: 取消变量的类型属性
-a: 将变量声明为数组型
-i: 将变量声明为整数型(integer)
-r: 讲变量声明为只读变量。注意,一旦设置为只读变量,既不能修改变量的值,也不能删除变量,甚至不能通过+r取消只读属性
-x: 将变量声明为环境变量
-p: 显示指定变量的被声明的类型

[kris@hadoop101 ~]$ a=11
[kris@hadoop101 ~]$ b=22
[kris@hadoop101 ~]$ declare -i c=$a+$b
[kris@hadoop101 ~]$ echo $c
33

数组变量类型

[kris@hadoop101 ~]$ name[0]="kris"
[kris@hadoop101 ~]$ name[1]="song"
[kris@hadoop101 ~]$ echo ${name}
kris
[kris@hadoop101 ~]$ echo ${name[0]}
kris
[kris@hadoop101 ~]$ echo ${name[1]}
song
[kris@hadoop101 ~]$ echo ${name[*]}
kris song

数组下标从0开始,调用数组时,需要使用 ${数组[下标]} 的方式读取;

 

[kris@hadoop101 ~]$ declare -x age=20 #把变量age声明为环境变量
[kris@hadoop101 ~]$ declare -r age #给age赋予只读属性
[kris@hadoop101 ~]$ age=30 #age变量的值就不能修改了
-bash: age: readonly variable
[kris@hadoop101 ~]$ declare +r age #也不能取消只读属性
-bash: declare: age: readonly variable
[kris@hadoop101 ~]$ unset age #也不能删除变量
-bash: unset: age: cannot unset: readonly variable
[kris@hadoop101 ~]$ echo $age
20


查询变量属性和取消变量属性
变量属性的查询使用“-p”选项,变量属性的取消使用“+”选项。
[kris@hadoop101 ~]$ declare -p c
declare -i c="33"
[kris@hadoop101 ~]$ declare -p name
declare -a name='([0]="kris" [1]="song")'
[kris@hadoop101 ~]$ declare -x age
[kris@hadoop101 ~]$ declare -p age
declare -rx age="20"

2)使用expr或let数值运算工具

要想进行数值运算的第二种方法是使用expr命令,这种命令就没有declare命令复杂了

[kris@hadoop101 ~]$ echo $a
11
[kris@hadoop101 ~]$ echo $b
22
[kris@hadoop101 ~]$ d=$(expr $a+$b)
[kris@hadoop101 ~]$ echo $d
11+22
[kris@hadoop101 ~]$ d=$(expr $a + $b)  # + 号左右要有空格;
[kris@hadoop101 ~]$ echo $d          
33
[kris@hadoop101 ~]$ let e=$a+$b
[kris@hadoop101 ~]$ echo $e
33

n=20                     #定义变量n
let n+=1                #变量n的值等于变量本身再加1
echo $n
    21

3)使用“$((运算式))” 或 “$[运算式]”方式运算

其实这是一种方式“$(())”和“$[]”这两种括号按照个人习惯使用即可

[kris@hadoop101 ~]$ f=$(( $a+$b ))
[kris@hadoop101 ~]$ echo $f
33
[kris@hadoop101 ~]$ g=$[ $a+$b ]
[kris@hadoop101 ~]$ echo $g
33

这三种数值运算方式,按照自己的习惯来使用。推荐使用“$((运算式))”的方式

常用运算符

优先级 运算符 说明
13 -,+ 单目负、单目正
12 !,~ 逻辑非、按位取反或补码
11 * , / , % 乘、除、取模
10 +, - 加、减
9 << , >> 按位左移、按位右移
8 < =, > =, < , > 小于或等于、大于或等于、小于、大于
7 == , != 等于、不等于
6 & 按位与
5 ^ 按位异或
4 | 按位或
3 && 逻辑与
2 || 逻辑或
1 =,+=,-=,*=,/=,%=,&=, ^=, |=, <<=, >>= 赋值、运算且赋值

运算符优先级表明在每个表达式或子表达式中哪一个运算对象首先被求值,数值越大优先级越高,具有较高优先级级别的运算符先于较低级别的运算符进行求值运算。

 

环境变量配置文件

source命令
[root@localhost ~]# source 配置文件
  或
[root@localhost ~]# . 配置文件

环境变量配置文件

1)登录时生效的环境变量配置文件

在Linux系统登录时主要生效的环境变量配置文件有以下五个:

  • /etc/profile
  • /etc/profile.d/*.sh
  • ~/.bash_profile
  • ~/.bashrc
  • /etc/bashrc

环境变量配置文件调用过程:

 Linux| 变量| 流程控制| shell工具-cut sed awk sort

① 在用户登录过程先调用/etc/profile 文件

在这个环境变量配置文件中会定义这些默认环境变量:

  • USER变量:根据登录的用户,给这个变量赋值(就是让USER变量的值是当前用户)。
  • LOGNAME变量:根据USER变量的值,给这个变量赋值。
  • MAIL变量:根据登录的用户,定义用户的邮箱为/var/spool/mail/用户名。
  • PATH变量:根据登录用户的UID是否为0,判断PATH变量是否包含/sbin、/usr/sbin和/usr/local/sbin这三个系统命令目录。
  • HOSTNAME变量:更加主机名,给这个变量赋值。
  • HISTSIZE变量:定义历史命令的保存条数。
  • umask:定义umask默认权限。注意/etc/profile文件中的umask权限是在“有用户登录过程(也就是输入了用户名和密码)”时才会生效。

调用/etc/profile.d/*.sh文件,也就是调用/etc/profile.d/目录下所有以.sh结尾的文件。

② 由/etc/profile文件调用/etc/profile.d/*.sh文件 

这个目录中所有以.sh结尾的文件都会被/etc/profile文件调用,这里最常用的就是lang.sh文件,而这个文件又会调用/etc/sysconfig/i18n文件。/etc/sysconfig/i18n这个文件是默认语系配

置文件。

③ 由/etc/profile文件调用~/.bash_profile文件,~/.bash_profile文件就没有那么复杂了,这个文件主要实现了两个功能:

  • 调用了~/.bashrc文件。
  • 在PATH变量后面加入了“:$HOME/bin”这个目录。即如果我们在自己的家目录中建立bin目录,把自己的脚本放入“~/bin”目录,就可以直接执行脚本,而不用通过目录执行了。

④ 由~/.bash_profile文件调用~/.bashrc文件,在~/.bashrc文件中主要实现了:

  • 定义默认别名,所以可以把自己定义的别名放入这个文件
  • 调用/etc/bashrc

⑤ 由~/.bashrc调用了/etc/bashrc文件,在/etc/bashrc文件中主要定义了这些内容:

   PS1变量:也就是用户的提示符,如果我们想要永久修改提示符,就要在这个文件中修改

   umask:定义umask默认权限。这个文件中定义的umask是针对“没有登录过程(也就是不需要输入用户名和密码时,比如从一个终端切换到另一个终端,或进入子Shell)”时生

效的。如果是“有用户登录过程”,则是/etc/profile文件中的umask生效。

  PATH变量:会给PATH变量追加值,当然也是在“没有登录过程”时才生效。

⑥ 调用/etc/profile.d/*.sh文件,这也是在“没有用户登录过程”时才调用。在“有用户登录过程”时,/etc/profile.d/*.sh文件已经被/etc/profile文件调用过了。

     这五个环境变量配置文件会被依次调用,如果是我们自己定义的环境变量应该放入哪个文件呢?

  • 如果你的修改是打算对所有用户生效的,那么可以放入/etc/profile环境变量配置文件;
  • 如果你的修改只是给自己使用的,那么可以放入~/.bash_profile或~/.bashrc这两个配置文件中的任一个。

可是如果我们误删除了这些环境变量,比如删除了/etc/bashrc文件,或删除了~/.bashrc文件,那么这些文件中配置就会失效(~/.bashrc文件会调用/etc/bashrc文件)。

那么我们的提示符就会变成: -bash-4.1#

2)、 注销生效的环境变量配置文件

在用户退出登录时,只会调用一个环境变量配置文件,就是~/.bash_logout。这个文件默认没有写入任何内容,可是如果我们希望再退出登录时执行一些操作,比如清除历史命令,备

份某些数据,就可以把命令写入这个文件。

3)、 其他配置文件

还有一些环节变量配置文件,最常见的就是~/bash_history文件,也就是历史命令保存文件。这

个文件已经讲过了,这里我们只是把它归入环境变量配置文件小节而已。

 

 

 

 

1. 流程控制

if 判断

1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
(2)if后要有空格

[kris@hadoop datas]$ vim if.sh 
#!/bin/bash
if [ $1 -eq "1" ]
then
        echo "one"
elif [ $1 -eq "2" ]
then
        echo "two"
else
        echo "other"
fi
-------------------
#!/bin/bash
if [ $1 -eq "1" ]; then echo "one"
fi

      运算式$[4%2] 和表达式[ 4 -eq 3 ],注意区别  

for循环和if的使用


表达式
[kris@hadoop datas]$ vi for.sh 
#!/bin/bash

for ((i=0;i<10;i++))
do
        if [ $[$i%2] -eq 0 ]
        then
        echo $i
fi
done

或者这样写:
for ((i=0;i<10;i++))
do
        if [ $(($i%2)) = 0 ]; then echo $i
     fi
done

[kris@hadoop datas]$ sh for.sh 
0
2
4
6
8

#!/bin/bash
for((i=0;i<10;i++))
do
        if [ $(($i%2)) = 0 ]; then echo $i
        elif [ $(($i%3)) = 0 ]; then echo $i
        else echo "我是奇数"
fi
done

case

#!/bin/bash
case $1 in
"1")
        echo "Monday"
;;
"2")
        echo "Tuesday"
;;
"3")
        echo "Wednesday"
;;
"4")
        echo "Thursday"
;;
"5")
        echo "Friday"
;;
*)
        echo "Weekend"
;;
esac

[kris@hadoop datas]$ ./case.sh 3
Wednesday

while循环

[kris@hadoop datas]$ vim while.sh 
#!/bin/bash
i=1
s=0
while [ $i -le 100 ]
do
  s=$[$s+$i]
  i=$[$i+1]
done
echo $s
[kris@hadoop datas]$ sh while.sh 3333333333
5050

 

函数function

bash 可以进入子shell,exit是退出来,

source a.sh是在当前shell执行
./a.sh是在子shell中执行的

export 使得当前shell和子shell中定义的变量都起作用

 系统函数

basename [string / pathname] [suffix] 
(功能描述:basename命令会删掉所有的前缀包括最后一个(‘/’)字符,然后将字符串显示出来。
suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。

[kris@hadoop datas]$ basename /home/kris/datas/while.sh
while.sh
[kris@hadoop datas]$ basename /home/kris/datas/while.sh .sh
while

dirname 文件绝对路径        (功能描述:从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录的部分))
[kris@hadoop datas]$ dirname /home/kris/datas/while.sh  
/home/kris/datas

自定义函数

必须在调用函数地方之前,先声明函数,shell脚本是逐行运行。不会像其它语言一样先编译。
函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255)

#/bin/bash
function sum()
{
        s=$echo $s
}
sum $1 $2
~                                                                               
~                                                                                                           
[kris@hadoop datas]$ 
[kris@hadoop datas]$ sh function.sh 1 3
4

2. shell工具 

cut

cut的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。

-f (列号,提取第几列)   -d(分隔符,按照指定分隔符分割列)    -c   (指定具体字符,如5--9个字符)


[root@kris datas]# ifconfig | grep Bcast 
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
[root@kris datas]# ifconfig | grep Bcast | cut -c 11-14
inet

[root@kris ~]# ifconfig | grep Bcast | cut -d : -f 2
192.168.1.100  Bcast
[root@kris ~]# ifconfig | grep Bcast | cut -d : -f 2 | cut -d " " -f 1 
192.168.1.100
[root@kris datas]# ifconfig | grep Bcast > temp.log  ##### > 是把原来的内容覆盖、>>是在原内容基础上追加; 
[root@kris datas]# cat temp.log 
          inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
[root@kris datas]# cut -d : -f 2 temp.log          
192.168.1.100  Bcast
[root@kris datas]# cat temp.log | cut -d : -f 2  #####与上边是的等效的,只是temp.log所放的位置不一样
192.168.1.100  Bcast
[root@kris datas]# ifconfig | grep Bcast | cut -d : -f 2 | cut -d " " -f 3
Bcast

 

 sed

sed按行处理;

sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出

 -e(直接在指令列模式上进行sed的动作编辑;两个修改指令的方式)  -i (在文件中直接编辑修改文件)   

a(新增,a的后面可以接字串,在下一行出现 '2axxxx' )  d (删除)

 s(查找并替换 ‘s/Link/xxxx/’ 

ifconfig | sed '1d'    删除第一行

 ifconfig | sed '1,5d' 删除掉前5行

 ifconfig | sed '1akris'  在第一行后面(第二行)追加kris

ifconfig | sed 's/Link/XXX/' 查找并替换;注意是区分大小写的,最后的/符号不要忘记了ifconfig | sed 's/Link/XXX/' temp.log  #并不会改变文件内容

 ifconfig | sed -i 's/Link/XXX/' temp.log  加上-i就可以在文件中修改成功了;前提是文件中的内容必须是ifconfig输出内容;
ifconfig | sed  '/^ *R/aXXX'  前边有若干个空格,以R开头的

[root@kris datas]# ifconfig | sed -e '/^ *R/aXXX' -e'/^ *T/d'   
以R开头的追加XXX
,把以T开头的删掉;这是两个式子就不能通过一个式子搞定了,需加-e改变修改方式只有一个时可以省略;

 

 awk

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

按行处理,可以对行内的数据进行更细微的操作;

awk [选项参数] ‘pattern1{action1}  pattern2{action2}...’ filename

  pattern:表示AWK在数据中查找的内容,就是匹配模式

  action:在找到匹配内容时所执行的一系列命令

  选项参数:-F(指定输入文件折分隔符)、-v(赋值一个用户定义变量)

cp /etc/passwd ./
[root@kris datas]# cat passwd | awk '/^a/{print}' 把以a开头的打印出来 [root@kris datas]# cat passwd | awk '/^a/{print}'   adm:x:3:4:adm:/var/adm:/sbin/nologin   avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin   abrt:x:173:173::/etc/abrt:/sbin/nologin   apache:x:48:48:Apache:/var/www:/sbin/nologin [root@kris datas]# cat passwd | awk -F : '/^a/{print $1}' //-F指定输入文件折分隔符   adm   avahi-autoipd   abrt   apache [root@kris datas]# cat passwd | awk -F: '/^a/{print $1} /^adm/{print}' 如果匹配到了以a开头就把print $1打印出来; 如果又匹配到了adm就把print整行打印出;

  adm
  adm:x:3:4:adm:/var/adm:/sbin/nologin
  avahi-autoipd
  abrt
  apache
  alex

#如果不写模板它就把所有行都打印出
[root@kris datas]# cat passwd | awk -F : '{print $1}'   ...... [root@kris datas]#
cat passwd | awk -F: 'BEGIN{print "begin"} {print$1} END{print "end"}'
  #begin在数据输入之前先执行BEGIN这个块里边的;END是所有数据处理完了再执行这个块里边的东西;
  begin
  ...
  end

 [kris@hadoop datas]$ cat passwd
  root:x:0:0:root:/root:/bin/bash
  bin:x:1:1:bin:/bin:/sbin/nologin
  daemon:x:2:2:daemon:/sbin:/sbin/nologin
  adm:x:3:4:adm:/var/adm:/sbin/nologin
  lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  sync:x:5:0:sync:/sbin:/bin/sync
  shutdown:x:6:0:sh.....

[root@kris datas]# cat passwd | awk -F: 'BEGIN{sum=0;print "Sum="sum} {sum+=$3} END{print "Sum="sum}'  #把第3列的数值加到sum上,对文件的第3列做累加;
  Sum=0
  Sum=3222
[root@kris datas]# cat passwd | awk -F: 'BEGIN{sum=0;print "Sum="sum} {sum+=$3; print $3"Sum="sum} END{print "Sum="sum}' ###上面求和的过程


[root@kris datas]# which awk
/bin/awk
[root@kris datas]# ll /bin/awk
lrwxrwxrwx. 1 root root 4 9月   3 2013 /bin/awk -> gawk  
[root@kris datas]# cat passwd | awk -F: -v sum=0 'BEGIN{print "Sum="sum} {sum+=$3; print $3"Sum="sum} END{print "Sum="sum}'  #-v就是引入一个变量


awk的内置变量
[root@kris datas]# cat temp | awk 'BEGIN{sum=0}{sum+=1}/^$/{print sum}'  #打印出文件的所有空行的行号,下面这种方法更简单;

[root@kris datas]# cat temp | awk '/^$/{print NR}' #NR就起到sum的作用; 也可这样写: awk '/^$/{print NR}' temp
2
3
5
7
8
10
11
12

[root@kris datas]# awk '/^$/{print FILENAME}' temp  ##每列输出文件名
temp
temp
temp


[root@kris datas]# awk -F : '{print NF}' passwd   #######NF是按:切割的列数,一共多少列;  
7
7
7
...

[root@kris datas]# awk -F: '{print "filename:" FILENAME ", linenumber:" NR ",columns:"NF}' passwd 
filename:passwd, linenumber:1,columns:7
filename:passwd, linenumber:2,columns:7
filename:passwd, linenumber:3,columns:7
[root@kris datas]# ifconfig  eth0 | grep "inet addr" | awk -F: '{print $2}'
192.168.1.100  Bcast
[root@kris datas]# ifconfig  eth0 | grep "inet addr" | awk -F: '{print $2}' | awk -F " " '{print $1}'
192.168.1.100

 

一个目录下(包括子目录)一共有多少个java文件? 如何取得每一个文件的名称? 
[kris@hadoop ~]$ sudo find / -name "*.java"
/root/anaconda3/pkgs/spyder-3.3.2-py37_0/lib/python3.7/site-packages/spyder/utils/tests/data/example.java
/root/anaconda3/lib/python3.7/site-packages/spyder/utils/tests/data/example.java
[kris@hadoop ~]$ sudo find / -name "*.java" | awk -F "/" '{print $NF}'  以/切割,NF这行一共有多少列,如一共8列,$NF表取第8列
example.java
example.java

 [kris@hadoop ~]$ basename /opt/module/hive
  hive

 

 

practice

使用Linux命令查询file1中空行所在的行号
[krs@hadoop101 datas]$ awk '/^$/{print NR}' file1.txt 
5
1.有文件chengji.txt内容如下:
张三 40
李四 50
王五 60

使用Linux命令计算第二列的和并输出
[kris@hadoop datas]$ cat chengji.txt | awk -F " " '{sum+=$2} END{print sum}'   ######### -F " " $2 分割的列不是从0开始数的,从1开始
150

2.用shell写一个脚本,对文本中无序的一列数字排序
[kris@hadoop datas]$ sort -n text.txt 
1
2
3
4
5
6
7
8
9
10

[kris@hadoop datas]$ sort -n text.txt | awk '{sum+=$0; print $0} END{print "sum="sum}'

  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  sum=55

3 用shell脚本写出查找当前文件夹(/home)下所有的文本文件内容中包含有字符”kris”的文件名称
  [kris@hadoop datas]$ grep -r "kris" /home/ | cut -d : -f 1

 

sort

-n(依照数值的大小排序) 、  -r (以相反的顺序来排序) 、 -t (设置排序时所用的分隔字符) 、 -k(指定需要排序的列)

[root@kris datas]# cat passwd | grep ^a | sort -t : -k 3
avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
[root@kris datas]#
cat passwd | grep ^a | sort -t : -k 3 -n   adm:x:3:4:adm:/var/adm:/sbin/nologin   apache:x:48:48:Apache:/var/www:/sbin/nologin   avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin   abrt:x:173:173::/etc/abrt:/sbin/nologin
[root@kris datas]#
cat passwd | grep ^a | sort -t : -k 3 -nr abrt:x:173:173::/etc/abrt:/sbin/nologin avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin apache:x:48:48:Apache:/var/www:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin [root@kris datas]# sort -t : -nrk 3 sort.sh bb:40:5.4 bd:20:4.2 cls:10:3.5 xz:50:2.3 ss:30:1.6

相关文章:

  • 2022-01-16
  • 2022-12-23
  • 2022-01-03
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-09-14
猜你喜欢
  • 2021-09-09
  • 2022-12-23
  • 2022-12-23
  • 2021-09-14
  • 2021-08-28
  • 2021-08-24
  • 2021-11-30
相关资源
相似解决方案