文章目录

  • 文件描述符
  • 自定义文件描述符
  • 数组和关联数组
    • 定义关联数组
  • 别名
  • 获取终端信息
  • 获取,设置日期与延时
    • 延时
  • 调试脚本
  • 函数与参数
    • 递归函数
    • 导出函数
  • 读取命令序列输出
  • 不按回车键的方式读取字符“n”
  • 字段分隔符与迭代器
  • for循环
  • 命令使用
    • cat 查看
    • script,scriptreplay - 录制与查看终端会话
    • find 文件查找
    • xargs 格式化从标准输出的数据,传递给下一个参数
    • tr 转换
    • sort,uniq 排序单一,与重复
    • uniq 消除重复行
  • 校验和与核实
  • 临时文件命名与随机随机数
  • 分割文件与日志
    • dd 拷贝与转换文件
    • split 切割文件
    • csplit 根据文本特点分割文件
      • 根据扩展名提取文件名
  • 批量重命名与移动
  • 交互输入自动化
    • read 从标准输入中读取数值
  • 文件管理
    • 生成任意大小的文件
    • 文本文件的交集与差集
      • comm 比较差异
    • 查找并删除重复文件
    • 创建不可删除文件
      • chattr 修改文件属性
    • 批量生成空白文件
      • touch 创建文件
    • 列举文件类型统计信息
      • file 识别文件类型

篇幅较长,可能还有后续更新,建议收藏
此篇是我读《 linux shell 脚本攻略》所写的的个人笔记
文章主体脉络由书中得来
相关命令用法由书中或互联网或系统帮助,或个人实验得来
例子由自己编写而来

我为什么都标个人原创?

1.本人所有文章都是个人笔记,不是专业写博客的
2.此文章不产生任何盈利,与原书也发生不了任何纠纷
3.例子,命令用法,注释都是个人编写
4.例如此书,转载必须填写原网址,我该如何填写一本书的网址?
5.文章内容可能从一篇,或者很多篇博客,书籍,又或者是系统命令帮助而来,我没有很多精力来记录他们,或者询问能否转载

写博客的意义
1.所有文章只是作为个人在线笔记
2.投公开发表是觉得可能会对初学者提供一些帮助

文件描述符

文件描述符是与一个打开的文件或数据流相关联的整数。也是用于访问文件的一个抽象指针。存取文件离不开被称为“文件描述符”的特殊数字。0、1和2分别是stdin、stdout和stderr的预留描述符。

  • 0——stdin(标准输人)
  • 1——stdout(标准输出)
  • 2——stderr(标准错误)

例如我们在源码安装mysql初始化的时候会有密码需要暂时保存一下那我们可以使用echo将输出文本重定向到一个文件中

[root@zzyyssxx ~]# echo '123456' > pwd.txt
[root@zzyyssxx ~]# cat pwd.txt
123456
[root@zzyyssxx ~]# echo 'abcdef' >>  pwd.txt
[root@zzyyssxx ~]# cat pwd.txt
123456
abcdef
[root@zzyyssxx ~]# echo '2233' >  pwd.txt
[root@zzyyssxx ~]# cat pwd.txt
2233

和>>并不相同。尽管这两个操作符都可以将文本重定向到文件,但是前者会先清空文件,再写入内容;而后者会将内容追加到现有文件的下一行。

当使用重定向操作符时,重定向的内容不会出现在终端,而是直接被导入文件。重定向操作符默认使用标准输出。如果想使用特定的文件描述符,你必须将描述符置于操作符之前。

相同的 > 等同于 1> ,>> 等同于 1>>

输入错误命令时会出现错误信息,同时会返回一个非0状态码

[root@zzyyssxx ~]# lshdfsjf
-bash: lshdfsjf: 未找到命令

这里我们输入一个不合规参数,会返回标准错误信息

[root@zzyyssxx ~]# ls +
ls: 无法访问+: 没有那个文件或目录
[root@zzyyssxx ~]# echo $?
2
[root@zzyyssxx ~]# ls + > out.txt
ls: 无法访问+: 没有那个文件或目录
[root@zzyyssxx ~]# cat out.txt
[root@zzyyssxx ~]# ls + 2> out.txt
[root@zzyyssxx ~]# cat out.txt
ls: 无法访问+: 没有那个文件或目录

显然的标准输出没有被写到文件里,标准错误被写到了文件里面

也可以将错误和输出重定向到不同的文件

cmd 2>stderr.txt 1>stdout.txt

也可以将stderr转换成stdout,然后重定向到一个文件中

cmd 2>&1 output.txt
或 cmd &> output.txt

当我们不想看到错误的输出时可以

cmd 2> /dev/null

dev/null是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null设备通常也被称为黑洞。

当对stderr或stdout进行重定向时,重定向的文本将传入文件。因为文本已经被重定向到文件中,也就没剩下什么东西可以通过管道(I)传给接下来的命令,而这些命令是通过stdin来接收文本的。。

tee命令可以一方面将数据重定向到文件,另一方面还可以提供一份重定向的数据副本作为后续命令的stdin

作用:从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件语法格式:tee [参数] [文件]常用参数:-a 附加到既有文件的后面,而非覆盖它
-i  忽略中断信号
— help  查看帮助信息
— version   显示版本信息
[root@zzyyssxx ~]# echo '123' | tee 1.txt 2.txt
123
[root@zzyyssxx ~]# ls
1.txt  2.txt
[root@zzyyssxx ~]# cat 1.txt
123
[root@zzyyssxx ~]# cat 2.txt
123

有时候,我们需要对文本块(多行文本)像标准输人一样进行重定向。考虑一个特殊情况:文本就位于shell脚本中。可以按照下面的方法成:

[root@zzyyssxx ~]# cat <<EOF> 123.txt
> 1
> 2
> 3
> EOF
[root@zzyyssxx ~]# ls
123.txt
[root@zzyyssxx ~]# cat 123.txt
1
2
3
[root@zzyyssxx ~]# cat 1.sh
#!/bin/bashcat <<EOF> 111.txt
a
b
c
EOF[root@zzyyssxx ~]# chmod +x 1.sh  #授权
[root@zzyyssxx ~]# ls
123.txt  1.sh
[root@zzyyssxx ~]# ./1.sh   #执行
[root@zzyyssxx ~]# ls
111.txt  123.txt  1.sh
[root@zzyyssxx ~]# cat 111.txt

自定义文件描述符

除了预留的0,1,2描述符,我们可以使用exec命令创建自定义的文件描述符。文件的打开模式通常来说,会使用3种模式。

  • 只读模式
  • 截断模式
  • 追加模式

exec命令用于调用并执行指定的命令,也可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端。

语法格式:exec [参数]常用参数:-c  在空环境中执行指定的命令
[root@zzyyssxx ~]# exec 3<111.txt  #使用文件描述符3打开并读取文件
[root@zzyyssxx ~]# cat <&3
a
b
c
//如果要再次读取就不能,需要再次通过exec重新分配文件扫描符
[root@zzyyssxx ~]# cat <&3//与find连用
[root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ls {} \;
/root/123.txt
/root/111.txt
//需要注意的是连用的时候要输入完整的命令
[root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ll {} \;
find: ‘ll’: 没有那个文件或目录
find: ‘ll’: 没有那个文件或目录
[root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ls -l {} \;
-rw-r--r-- 1 root root 6 4月  12 13:58 /root/123.txt
-rw-r--r-- 1 root root 6 4月  12 14:04 /root/111.txt

创建一个文件描述符用于写入(截断模式)

[root@zzyyssxx ~]# cat <&3
[root@zzyyssxx ~]# exec 3>111.txt
[root@zzyyssxx ~]# cat 111.txt
[root@zzyyssxx ~]# echo new >&3
[root@zzyyssxx ~]# cat 111.txt
new
[root@zzyyssxx ~]# exec 4>>111.txt
[root@zzyyssxx ~]# echo 110 >&4
[root@zzyyssxx ~]# cat 111.txt
new
old
110

数组和关联数组

数组是shell脚本重要的组成部分,它借助索引将多个独立数据存储为1个集合。

Bash同时支持普通数组和关联数组。普通数组只能使用整数作为数组索引
,而关联数组可以使用字符串作为数组索引。关联数组在很多操作中相当有用。Bash从4.0版本开始支持关联数组。

可以使用一列值定义一个数组,#这些值将会存储在以0为起始索引的连续位置上

[root@zzyyssxx ~]# array_var=(1 2 3 4 5)
[root@zzyyssxx ~]# echo ${array_var[0]}
1

另外,还可以将数组定义成一组索引-值

[root@zzyyssxx ~]# array_var[0]="a"
[root@zzyyssxx ~]# array_var[1]="b"
[root@zzyyssxx ~]# array_var[2]="c"
[root@zzyyssxx ~]# echo $array_var[2]  //不加括号会默认打印第一个索引的值
a[2]
[root@zzyyssxx ~]# echo ${array_var[2]}
c

以清单形式打印数组中所有值

[root@zzyyssxx ~]# echo ${array_var[*]}
a b c
[root@zzyyssxx ~]# echo ${array_var[@]}
a b c

打印数组长度,也就是元素个数

[root@zzyyssxx ~]# echo ${#array_var[@]}
3
[root@zzyyssxx ~]# echo ${#array_var[*]}
3

定义关联数组

在关联数组中,我们可以用任意的文本作为数组索引。而在普通数组中,只能用整数作为数组索引。关联数组需要先声明再使用。
首先,需要使用单独的声明语句将一个变量名声明为关联数组。声明语句如下:

[root@zzyyssxx ~]# declare -A acb_array
语法格式: declare [参数] [目录]declare: 用法:declare [-aAfFgilrtux] [-p] [name[=value] ...]常用参数:-a 声明数组变量
-f  仅显示函数
-F  不显示函数定义
-i  先计算表达式,把结果赋给所声明变量
-p  显示给定变量的定义的方法和值,当使用此选项时,其他的选项将被忽略
-r  定义只读变量
-x  将指定的Shell变量转换成环境变量
[root@zzyyssxx ~]# declare
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.46(2)-release'
CALSS_PATH=.:/usr/local/jdk1.8.0_221/lib/dt.jar:/usr/local/jdk1.8.0_221/lib/tools.jar:/usr/local/jdk1.8.0_221/jre/lib
COLUMNS=83
DIRSTACK=()
EUID=0
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=zzyyssxx
HOSTTYPE=x86_64
ID=0
IFS=$' \t\n'
JAVA_HOME=/usr/local/jdk1.8.0_221
......
USER=root
XDG_RUNTIME_DIR=/run/user/0
XDG_SESSION_ID=4097
_=-h
acb_array=()
array_var=([0]="a" [1]="b" [2]="c")
colors=/root/.dircolors

可以看到里面包含许多环境变量

[root@zzyyssxx ~]# declare -p SSH_CLIENT //这是ssh相关参数
declare -x SSH_CLIENT="39.170.63.135 58535 22"
[root@zzyyssxx ~]# echo $SSH_CLIENT
39.170.63.135 58535 22

篇幅有限,此处不过多描述

可以用两种方法将元素添加到关联数组中。

  • 1.用内嵌索引-值列表法,写一个索引-值列表:
[root@zzyyssxx ~]# acb_array=([index1]=jerry [index2]=tom)
  • 2.使用独立的索引-值进行赋值:
[root@zzyyssxx ~]# acb_array[ind1]=apple
[root@zzyyssxx ~]# acb_array[ind2]=orange
[root@zzyyssxx ~]# echo ${acb_array[ind2]}
orange
[root@zzyyssxx ~]# echo ${acb_array[ind1]}
apple
[root@zzyyssxx ~]# echo ${acb_array[0]} //直接打印索引0这里为空

每一个数组元素都有一个索引用于查找。普通数组和关联数组具有不同的索引类型。

//列出数组索引
[root@zzyyssxx ~]# echo ${!acb_array[*]}
index1 index2 ind1 ind2
[root@zzyyssxx ~]# echo ${!acb_array[@]}
index1 index2 ind1 ind2

别名

alias命令用来设置指令的别名。我们可以使用该命令可以将一些较长的命令进行简化。使用alias时,用户必须使用单引号 ‘ ‘ 将原来的命令引起来,防止特殊字符导致错误。

语法格式:alias [参数]常用参数:-p 打印已经设置的命令别名
[root@zzyyssxx ~]# alias -p
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'[root@zzyyssxx ~]# alias cd='cd $@;ls --color=auto' //添加别名
[root@zzyyssxx ~]# alias -p
alias cd='cd ;ls --color=auto'  //新添加的别名
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'//测试一下
[root@zzyyssxx ~]# cd /usr/local/
aegis         games                       lib      sbin
bin           include                     lib64    share
cloudmonitor  jdk1.8.0_221                libexec  src
etc           jdk-8u221-linux-x64.tar.gz  nginx

alias命令的作用只是暂时的。一旦关闭当前终端,所有设置过的别名就失效了。为了使别名设置一直保持作用,可以将它放入~.bashrc文件中。因为每当一个新的shell进程生成时,都会执行 ~/.bashr中的命令。

[root@zzyyssxx ~]# echo 'alias cd="cd $@;ls --color=auto"' >> ~/.bashrc  //新进程也同样生效

如果需要删除别名,只用将其对应的语句从~l.bashrc中删除,或者使用unalias命令。另一种创建别名的方法是定义一个具有新名称的函数,并把它写入 ~/.bashr

[root@zzyyssxx ~]#  alias rm='cp $@ ~/backup; rm $@'

这样写可以防止误操作,定期清理即可
当你创建别名时,如果已经有同名的别名存在,那么原有的别名设置将被新的取代。

别名也存在相关安全隐患,万一服务器被入侵常用命令修改为其他命令会造成巨大损失,轻则提桶跑路,重则背上法律责任。
那么,如果避免这一点呢,答案就是转义

[root@zzyyssxx ~]# cd /usr/local/
aegis         games                       lib      sbin
bin           include                     lib64    share
cloudmonitor  jdk1.8.0_221                libexec  src
etc           jdk-8u221-linux-x64.tar.gz  nginx
[root@zzyyssxx ~]# \cd /usr/local/
[root@zzyyssxx local]#

字符\对命令实施转义,使我们可以执行原本的命令,而不是这些命令的别名替身。

获取终端信息

编写命令行shell脚本的时候,总是免不了大量处理当前终端的相关信息,
比如行数、列数、光标位置和遮盖密码字段等。

put命令将通过 terminfo 数据库对您的终端会话进行初始化和操作。通过使用 tput,您可以更改几项终端功能,如移动或更改光标、更改文本属性,以及清除终端屏幕的特定区域。

语法格式:tput [参数]

setb 用于设置背景颜色
setf 用于设置前景颜色
cols 获取行数
lines 获取列数

获取,设置日期与延时

当我们备份数据库时一般需要根据日期以及时间来执行操作。而延时一般在监控任务脚本,比如每5秒执行一次脚本。

我们能够以多种格式打印日期,也可以在命令行中设置日期。在类UNIX系统中,日期被存储为一个整数,其大小为自世界标准时间1970年1月1日0时0分0秒起所流逝的秒数。这种计时方式称之为纪元时或UNIX时间,一般叫时间戳。


读取日期

[root@zzyyssxx ~]# date
2022年 04月 18日 星期一 09:17:16 CST
[root@zzyyssxx ~]# date +%s
1650244686

将得到的时间戳进行转换,因为用的是云主机所以不用校准时间

//输出给定日期的字符串
[root@zzyyssxx ~]# date --date "Jan 20 2010" +%A
星期三
[root@zzyyssxx ~]# date "+%d %B %Y"
18 四月 2022
[root@zzyyssxx ~]# date "+%Y %B %d"
2022 四月 18

类似的这样的脚本可以检查一组命令花费的时间

#!/bin/bashstart=$(date +%s)
commands;
end=$(date +%s)difference=$(( end -start ))echo time is $difference seconds

延时

编写以循环的方式监控脚本时,需要设置时间间隔,可以利用sleep来延时

[root@zzyyssxx ~]# cat test.sh
#!/bin/bash
echo -n count:
tput sc
count=0;
while true;
do
if [ $count -lt 30 ];then
let count++;
sleep 1;
tput rc
tput ed
echo -n $count;
else exit 0;
fi
done

变量count初始化为0,随后每循环一次便增加1。echo语句打印出count的值。我们用tput sc存储光标位置。在每次循环中,我们通过恢复之前存储的光标位置,在终端中打印出新的count值。恢复光标位置的命令是tput rc。tptit ed清除从当前光标位置到行尾之间的所有内容,使得旧的count值可以被清除并写人新值。循环内的1秒钟延时是通过sleep命令来实现的

调试脚本

调试功能是每一种编程语言都应该实现的重要特性之一,当出现一些始料未及的情况时,用它来生成脚本运行信息。调试信息可以帮你弄清楚是什么原因使得程序发生崩溃或行为异常。

//
[root@zzyyssxx ~]# sh -x test.sh
。。。。。。。略
+ echo -n 29
29+ true
+ '[' 29 -lt 30 ']'
+ let count++
+ sleep 1
+ tput rc
+ tput ed
+ echo -n 30
30+ true
+ '[' 30 -lt 30 ']'
+ exit 0

-x 将脚本中执行过的每一行都输出到stdout,当我们只关注脚本某些命令可以使用调试打印。

set -x:在执行时显示参数和命令
set +:禁止调试
set -v:当命令进行读取时显示输入
set +v:禁止打印输入
[root@zzyyssxx ~]# cat debug.sh
#!/bin/bashfor i in {1..6}
do
set -x
echo $i
set +x
doneecho "script executed"
[root@zzyyssxx ~]# sh -x debug.sh
+ for i in '{1..6}'
+ set -x
+ echo 1
1
+ set +x
+ echo 2
2
+ set +x
+ echo 3
3
+ set +x
+ echo 4
4
+ set +x
+ echo 5
5
+ set +x
+ echo 6
6
+ set +x
script executed

也可以利用shebang来调试,将#!/bin/bash变为 #!/bin/bash -xv

#!/bin/bash -xvfor i in {1..6}
do
set -x
echo $i
set +x
doneecho "script executed"[root@zzyyssxx ~]# chmod +x debug.sh
[root@zzyyssxx ~]# ./debug.sh
#!/bin/bash -xvfor i in {1..6}
do
set -x
echo $i
set +x
done
+ for i in '{1..6}'
+ set -x
+ echo 1
1
+ set +x
+ echo 2
2
+ set +x
+ echo 3
3
+ set +x
+ echo 4
4
+ set +x
+ echo 5
5
+ set +x
+ echo 6
6
+ set +xecho "script executed"
script executed

函数与参数

定义函数:

function  函数名 ()
{命令;
流程语句;
}

函数名 ()
{命令;
流程语句;
}

定义完函数后只需要使用函数名就可以调用某个函数

函数名 ;//调用函数

参数可以传递给函数,并由脚本进行访问

函数名 arg1 arg2 ; //传递参数
fname ( )
{echo $1, $2 ;       #访问参数1和参数2
echo " $@";       #以列表的方式一次性打印所有参数
echo "$*";          #类似于$0,但是参数被作为单个实体
return 0 ;           #返回值
}

参数可以传递给脚本并通过script :$0(脚本名)访问
$1是第一个参数。

$2是第二个参数。

$n是第n个参数。

“$@”被扩展成”$1" “$2” "$3"等。

"$”被扩展成"$1c$2c 3 " " 3" " 3""@”用得最多。由于"$"将所有的参数当做单个字符串,因此它很少被使用。

递归函数

在Bash中,函数同样支持递归(可以调用自身的函数)。例如,F( ) { echo $1; F hello;sleep 1; }。

  • Fork炸弹
:() { :|:& }; :

这个递归函数能够调用自身,不断地生成新的进程,最终造成拒绝式服务攻击(Dos)。函数调用前的&将子进程放入后台。因为这段代码会分支出大量的进程,所以被称为Fork炸弹。

http://en.wikipedia.org/wiki/Fork_bomb fork炸弹相关解释

可以通过ulimit -u 20来限制用户进程数量
永久生效可以

echo   '"用户名" - nproc 20 ' >> /etc/security/limits.conf

导出函数

函数也能像环境变量一样用export导出,这样一来函数的作用域就可以扩展到子进程中。

export -f 函数名

读取命令序列输出

shell脚本可以轻松地将多个命令或工具组合起来生成输出。一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递至另一个命令。

[root@localhost ~]# ls
anaconda-ks.cfg  nmap-7.92-1.x86_64.rpm
[root@localhost ~]# ls | cat -n        ## 管道符|将前一个命令的参数传给下一个命令1  anaconda-ks.cfg2  nmap-7.92-1.x86_64.rpm
[root@localhost ~]# ls | cat -n > out.txt
[root@localhost ~]# ls
anaconda-ks.cfg  nmap-7.92-1.x86_64.rpm  out.txt
[root@localhost ~]# cat out.txt 1  anaconda-ks.cfg2  nmap-7.92-1.x86_64.rpm3  out.txt##子shell
[root@localhost ~]# ouput=$(ls | cat -n)
[root@localhost ~]# echo $ouput
1 123.txt 2 anaconda-ks.cfg 3 nmap-7.92-1.x86_64.rpm 4 out.txt##反引用`在tab键上面
[root@localhost ~]# ouput=`ls | cat`
[root@localhost ~]# echo $ouput
123.txt anaconda-ks.cfg nmap-7.92-1.x86_64.rpm out.txt##加双引号保留换行符
[root@localhost ~]# abc=$(ls | cat -n)
[root@localhost ~]# echo "$abc"1  1232  123.txt3  anaconda-ks.cfg4  nmap-7.92-1.x86_64.rpm5  out.txt

不按回车键的方式读取字符“n”

read命令的功能是用于读取单行数据内容,一般是从标准输入中读取数值,用于给变量赋值。

|语法格式:read [参数]

常用参数: 说明
-a 定义一个数组,以空格为间隔符进行赋值
-d 定义一个结束标志
-p 设置提示信息
-e 在输入的时候可以使用命令补全功能
-n 定义输入文本的长度
-r 禁用转义符(\)
-s 输入字符不在屏幕显示
-t 限定最长等待时间
-u 从文件描述符中读入信息
[root@localhost ~]# read -n 2 asd  #-n指定2个字符, 输入2个字符后会自动回车
23[root@localhost ~]# echo $asd
23##静默输入
[root@localhost ~]# read -s pass  ##输入后不会显示在屏幕上
[root@localhost ~]# echo $pass
1234##添加提示信息
[root@localhost ~]# read -p "input:"
input:123##利用界定符代替回车结束输入
[root@localhost ~]# read -d ":" zxc   ##指定界定符为:
123:[root@localhost ~]# echo $zxc
123

字段分隔符与迭代器

[root@localhost ~]# cat test.sh
# !/bin/bash
#用途:演示IFS的用法
line="root:x :0:0:root:/root:/bin/bash"
oldIFS=$IFS;
IFS=":"
count=0
for item in $line;
do
[ $count -eq 0 ] && user=$item;
[ $count -eq 6 ] && shell=$item;
let count++
done;
IFS=$o1dIFS
echo $user \'s she1l is $shell;

for循环

[root@localhost ~]# for i in {a..z};do echo $i;done
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z[root@localhost ~]# for ((i=0;i<10;i++)) { echo $i; }
0
1
2
3
4
5
6
7
8
9##生成连续ip地址
[root@localhost ~]# for i in 192.168.15.{1..10};do echo $i;done
192.168.15.1
192.168.15.2
192.168.15.3
192.168.15.4
192.168.15.5
192.168.15.6
192.168.15.7
192.168.15.8
192.168.15.9
192.168.15.10##起始为1,步进为2,到10 结束
[root@localhost ~]# for i in $(seq 1 2 10);do echo $i;done
1
3
5
7
9

条件测试,循环等补充知识点

命令使用

cat 查看

[root@localhost ~]# cat passwd
root:x:0:0:root:/root:/bin/bashshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# cat -n passwd    ##显示行号包括所有空白行1  root:x:0:0:root:/root:/bin/bash2  3  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown4  5  halt:x:7:0:halt:/sbin:/sbin/halt6  7  mail:x:8:12:mail:/var/spool/mail:/sbin/nologin8  9  10  11  operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# cat -s passwd  ##压缩连续的空白行
root:x:0:0:root:/root:/bin/bashshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# cat  passwd | tr -s '\n'  ## tr -s 删除重复出现的字符序列
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

script,scriptreplay - 录制与查看终端会话

script命令可以用作交互终端会话过程的记录,保留用户输入和系统输出的全过程。以备之后查询与学习。

在下述语法中,输出文件是用于存储所有的上机会话过程。如果未指定输出文件,所有的会话过程将会写到当前工作目录的默认文件typescript中。

语法格式:script [参数] [文件]常用参数:
-a  把会话记录附加到typescript文件或指定的文件后面,保留先前的内容
-c  运行指定的命令而非交互shell
-r  子进程中返回退出代码
-f  如果需要在输出到日志文件的同时,也可以查看日志文件的内容
-q  可以使script命令以静默模式运行
-t  指明输出录制的时间数据
-V  输出script的版本信息,然后退出
-h  输出script的help信息,然后退出
[root@localhost ~]# which script
/usr/bin/script
[root@localhost ~]# which scriptreplay
/usr/bin/scriptreplay[root@localhost ~]# script -V
script,来自 util-linux 2.23.2
[root@localhost ~]# script
Script started, file is typescript
[root@localhost ~]# exit
exit
Script done, file is typescript
[root@localhost ~]# ll
总用量 8
-rw-r--r--. 1 root root 208 1月  14 22:31 passwd
-rw-r--r--. 1 root root 181 1月  17 18:01 typescript##静默模式
[root@localhost ~]# script -q
[root@localhost ~]# exit
exit
//没有任何提示[root@localhost ~]# script -c "ls -l"
Script started, file is typescript
总用量 4
-rw-r--r--. 1 root root 208 1月  14 22:31 passwd
-rw-r--r--. 1 root root   0 1月  17 22:40 typescript
Script done, file is typescript[root@localhost ~]# ls
passwd  typescript
[root@localhost ~]# cat typescript
脚本启动于 2024年01月17日 星期三 22时40分13秒
总用量 4
-rw-r--r--. 1 root root 208 1月  14 22:31 passwd
-rw-r--r--. 1 root root   0 1月  17 22:40 typescriptScript done on 2024年01月17日 星期三 22时40分13秒
//没加-a之前的内容全被清空了 相当于重定向[root@localhost ~]# script -t 2> time.log -a typescript  ## -t将时序导入stderr,2> 将stderr导入time.log
Script started, file is typescript
[root@localhost ~]# ls
passwd  time.log  typescript
[root@localhost ~]# touch 123
[root@localhost ~]# ls
123  passwd  time.log  typescript
[root@localhost ~]# exit
exit
Script done, file is typescript
[root@localhost ~]# ls
123  passwd  time.log  typescript
[root@localhost ~]# cat time.log   //时间序列数据
0.605960 49
0.031052 1
2.154059 1
0.127346 2
0.248924 30
0.002781 41
0.000425 1
1.548721 1
0.151315 1
0.223722 1
0.209794 1
0.142308 1
0.288548 1
1.160007 1
0.359510 4
0.672967 1
0.247383 4
0.632045 1
0.112081 1
0.216661 2
0.497288 41
0.002472 1
1.507865 1
0.183600 2
0.448379 35
0.002940 41
0.000538 1
2.332258 1
0.247890 1
0.151661 1
0.169472 8
[root@localhost ~]# cat typescript
脚本启动于 2024年01月17日 星期三 22时40分13秒
总用量 4
-rw-r--r--. 1 root root 208 1月  14 22:31 passwd
-rw-r--r--. 1 root root   0 1月  17 22:40 typescriptScript done on 2024年01月17日 星期三 22时40分13秒
脚本启动于 2024年01月17日 星期三 22时43分36秒
[root@localhost ~]# ls
passwd  time.log  typescript
[root@localhost ~]# touch 123
[root@localhost ~]# ls
123  passwd  time.log  typescript
[root@localhost ~]# exit
exitScript done on 2024年01月17日 星期三 22时43分51秒
// 未设置时间同步[root@localhost ~]# scriptreplay time.log typescript   //按时间序列数据回放
总用量 4
-rw-r--r--. 1 root root 208 1月  14 22:31 passwd
-rw-r--r--. 1 root root   0 1月  17 22:40 typescriptScript done on 2024年01月17日 星期三 22时40分13秒
脚本启动于 2024年01月17日 星期三 22时43分36秒

find 文件查找

find命令的功能是根据给定的路径和条件查找相关文件或目录,可以使用的参数很多,并且支持正则表达式,结合管道符后能够实现更加复杂的功能,是系统管理员和普通用户日常工作必须掌握的命令之一。

语法格式:find [路径] [参数]常用参数:
-name   匹配名称
-iname 匹配名称且忽略大小写
-perm   匹配权限(mode为完全匹配,-mode为包含即可)
-user   匹配所有者
-group  匹配所有组
-mtime -n +n   匹配修改内容的时间(-n指n天以内,+n指n天以前)
-atime -n +n   匹配访问文件的时间(-n指n天以内,+n指n天以前)
-ctime -n +n   匹配修改文件权限的时间(-n指n天以内,+n指n天以前)
-nouser 匹配无所有者的文件
-nogroup    匹配无所有组的文件
-newer f1 !f2   匹配比文件f1新但比f2旧的文件
-type b/d/c/p/l/f   匹配文件类型(后面的字幕字母依次表示块设备、目录、字符设备、管道、链接文件、文本文件)
-size   匹配文件的大小(+50KB为查找超过50KB的文件,而-50KB为查找小于50KB的文件)
-prune  忽略某个目录
-exec …… {}\;   后面可跟用于进一步处理搜索结果的命令
[root@localhost ~]# find . -print  ##打印当前目录下所有文件
.
./.bash_logout
./.bash_profile
./.bashrc
./.cshrc
./.tcshrc
./.bash_history
./passwd
./.viminfo
./typescript
./time.log
./123
//-print是默认的不加也可以##反向匹配所有不以log结尾的
[root@localhost ~]# find .  ! -name "*.log"
.
./.bash_logout
./.bash_profile
./.bashrc
./.cshrc
./.tcshrc
./.bash_history
./passwd
./.viminfo
./typescript
./123##路径匹配
[root@localhost ~]# find / -path "*sysconfig*"
find: ‘/proc/15773’: 没有那个文件或目录
/run/initramfs/state/etc/sysconfig
/run/initramfs/state/etc/sysconfig/network-scripts
/etc/sysconfig
/etc/sysconfig/ip6tables-config
/etc/sysconfig/iptables-config
。。。## 基于目录深度的搜索
[root@localhost ~]# find / -maxdepth 1 -type f
/nohup_xxl-job-admin.log
[root@localhost ~]# find / -maxdepth 2 -type f
/boot/.vmlinuz-3.10.0-693.el7.x86_64.hmac
/boot/System.map-3.10.0-693.el7.x86_64
/boot/config-3.10.0-693.el7.x86_64
/boot/symvers-3.10.0-693.el7.x86_64.gz
/boot/vmlinuz-3.10.0-693.el7.x86_64
。。。##-newer 找出比对比文件更长的文件
[root@localhost ~]# find . -type f -newer time.log
./.bash_history
./passwd
./.viminfo
./typescript
./123##-delete 删除找出的文件
[root@localhost ~]# find . -type f   -newer time.log -delete
[root@localhost ~]# ls
time.log##-exec 表示将找到的文件交给下一步{} 代表找到的文件
[root@localhost ~]# find . -type f  -name "*.log" -exec mv {} 123 \;
[root@localhost ~]# ls
123

xargs 格式化从标准输出的数据,传递给下一个参数

xargs命令默认接收的信息中,空格是默认定界符,所以可以接收包含换行和空白的内容。

[root@localhost ~]# find . -type f -name "*.txt" -print | xargs echo
./abc.txt ./123.txt[root@localhost ~]# find . -type f -name "*.txt" -print | xargs  rm -f
[root@localhost ~]# ls
123

tr 转换

r命令是一款批量字符转换、压缩、删除的文本工具,但仅能从标准输入中读取文本内容,需要与管道符或输入重定向操作符搭配使用。

语法格式:tr [参数] 字符串1 字符串2常用参数:
-c  反选字符串1的补集(取反)
-d  删除字符串1中出现的所有字符
-s  删除所有重复出现的字符序列
##大小写转换
[root@localhost ~]# echo "HELLO WORLD" | tr 'A-Z' 'a-z'
hello world
[root@localhost ~]# echo "HELLO WORLD" | tr L l
HEllO WORlD
[root@localhost ~]# echo "HELLO WORLD" | tr H h
hELLO WORLD##通过数字映射加密
[root@localhost ~]# echo 12345 | tr '0-9' '9876543210'
87654               ##已加密 通过映射将原来的12345转换为87654##反过来替换解密
[root@localhost ~]# echo 87654  | tr '9876543210' '0-9'
12345##删除不想要的数据
[root@localhost ~]# echo "Hello 123 world 456" |  tr -d '0-9'
Hello  world       ##将stdin中的数字删除并打印出来##字符串补集
[root@localhost ~]# echo hello 1 char 2 next 3 | tr -d -c '0-9 \n'1  2  3
[root@localhost ~]# echo hello 1 char 2 next 3 | tr -d -c '0-9'
123##压缩连续的重复字符
[root@localhost ~]# echo hello      char    next  | tr -s ' '
hello char next
//压缩的重复的连续空格

简单实践

//计算下列数字和
[root@localhost ~]# cat sum.txt
1
2
3
4
5
7
9
[root@localhost ~]# cat sum.txt | echo $[ $(tr '\n' '+') 0 ]
31
//将每行的换行符替换为+号,但是最后一行9+ 没有操作数所有需要在外面加个0
  • tr可以像使用集合一样使用各种不同的字符类,这些字符类如下所示。
xdigit 十六进制字符
alnum 字母和数字
alpha 字母
cntrl 控制(非打印)字符
digit 数字
grap 图形字符
lower 小写字母
print 可打印字符
punct 标点符号
space 空白字符
upper 大写字母
[root@localhost ~]# echo hello 1 char 2 next 3 | tr '[:lower:]' '[:upper:]'
HELLO 1 CHAR 2 NEXT 3
//小写转大写

sort,uniq 排序单一,与重复

语法格式:sort [参数] 文件常用参数:
-b  忽略每行前面开始出的空格字符
-c  检查文件是否已经按照顺序排序
-d  除字母、数字及空格字符外,忽略其他字符
-f  将小写字母视为大写字母
-i  除040至176之间的ASCII字符外,忽略其他字符
-m  将几个排序号的文件进行合并
-M  将前面3个字母依照月份的缩写进行排序
-n  依照数值的大小排序
-o <输出文件> 将排序后的结果存入制定的文件
-r  以相反的顺序来排序
-t <分隔字符> 指定排序时所用的栏位分隔字符
-k  指定需要排序的栏位
##按字母排序
[root@localhost ~]# cat apple.txt
banana
pear
apple
orange
raspaberry
[root@localhost ~]# sort apple.txt
apple
banana
orange
pear
raspaberry##按开头数字排序
[root@localhost ~]# cat number.txt
45
12
3
98
82
67
24
56
9
2324
2
4
a
c
bc
a
[root@localhost ~]# sort number.txt
12
2
2324
24
3
4
45
56
67
82
9
98
a
a
bc
c##按数字大小排序
[root@localhost ~]# sort -n number.txt
a
a
bc
c
2
3
4
9
12
24
45
56
67
82
98
2324##通过列进行排序
[root@localhost ~]# cat data.txt
1   centos  790
2   linux   300
3   euleros 500
4   ubantu  1000
5  oracle   501
6   unix     10000
[root@localhost ~]# sort -nk 1 data.txt //n以大小排序 k指定列
1   centos  790
2   linux   300
3   euleros 500
4   ubantu  1000
5  oracle   501
6   unix     10000[root@localhost ~]# sort -nk 3 data.txt
2   linux   300
3   euleros 500
5  oracle   501
1   centos  790
4   ubantu  1000
6   unix     10000
[root@localhost ~]# sort -nkr 3 data.txt  //k指定行号 放最后面
sort: 区块起始处的编号无效:在"r" 处的计数无效
[root@localhost ~]# sort -nrk 3 data.txt
6   unix     10000
4   ubantu  1000
1   centos  790
5  oracle   501
3   euleros 500
2   linux   300

uniq 消除重复行

语法格式:uniq [参数] 文件常用参数:
-c  打印每行在文本中重复出现的次数
-d  每个重复纪录只出现一次
-u  只显示没有重复的纪录
[root@localhost ~]# cat cont.txt
hack
hack
apple
oppo
xiaomi
apple[root@localhost ~]# uniq cont.txt  ##消除相邻重复行
hack
apple
oppo
xiaomi
apple[root@localhost ~]# uniq -c  cont.txt ##消除重复行并统计重复次数,空行也算2 hack1 apple1 oppo1 xiaomi1 apple1 [root@localhost ~]# sort cont.txt | uniq -d  ##打印文件重复行
apple
hack

校验和与核实

校验和(checksum)程序用来从文件中生成校验和密钥,然后利用这个校验和密钥核实文件完整性。一份文件可以通过网络或任何存储介质分发到不同的地点。出于多种原因,数据有可能丢失或损坏。这时就需要利用校验和来验证文件完整性,特别是数据库备份脚本。

-md5sum 一个32字符的16进制串

[root@localhost ~]# md5sum sum.txt
d6fcd506544a5b3a46f7f9d21dced3cf  sum.txt
[root@localhost ~]# md5sum sum.txt > sum.md5
[root@localhost ~]# md5sum -c sum.md5
sum.txt: 确定

-sha1sum 一个40字符的16进制串

[root@localhost ~]# sha1sum sum.txt
b5a29a0473702a7a3a2068aa55bc5a8fe7bb0592  sum.txt
[root@localhost ~]# sha1sum sum.txt > sum.sha1
[root@localhost ~]# sha1sum -c sum.sha1
sum.txt: 确定

临时文件命名与随机随机数

编写shell脚本时,我们经常需要存储临时数据。最适合存储临时数据的位置是/tmp(该目录中的内容在系统重启后会被清空)。有两种方法可以为临时数据生成标准的文件名。

  • 利用随机数
[root@localhost ~]# echo $RANDOM  ##返回一个随机数
991temp_file=" / tmp /file-$RANDOM"
  • 利用进程id
temp_file=" /tmp/var.s$"  ##.$$ 作为添加的后缀会被扩展成当前运行脚本的进程ID。[root@localhost ~]# cat test.sh
#!/bin/shtemp_file=/tmp/var.$$
echo $temp_file[root@localhost ~]# chmod +x test.sh
[root@localhost ~]# ./test.sh
/tmp/var.12280

分割文件与日志

dd 拷贝与转换文件

dd命令来自于英文词组“disk dump”的缩写,其功能是用于拷贝及转换文件。使用dd命令可以按照指定大小的数据块来拷贝文件,并在拷贝的过程中对内容进行转换。语法格式:dd 参数 对象常用参数:
-v  显示版本信息
-h  显示帮助信息
[root@localhost ~]# dd if=/dev/zero bs=100k count=1 of=data.file
记录了1+0 的读入
记录了1+0 的写出
102400字节(102 kB)已复制,0.000726083 秒,141 MB/秒
[root@localhost ~]# ls
data.file
[root@localhost ~]# du -sh *   ##查看文件大小
100K    data.file

split 切割文件

split命令可以将大文件分割成较小的文件,在默认情况下将按照每1000行切割成一个小文件 。语法格式:split [参数] [切割文件][文件名]常用参数:
-b  指定每多少字节切成一个小文件
--help  查看帮助信息
--version   显示版本信息
-C  与参数”-b”相似,但是在切割时将尽量维持每行的完整性
-d   后缀使用数字
-a   指定后缀长度
-l   指定行数分割
[root@localhost ~]# split -b 10k data.file  ##以10k切割
[root@localhost ~]# ls
data.file  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj[root@localhost ~]# split -b 10k data.file -d -a 3 ##-d以数字切割 -a 指定后缀长度
[root@localhost ~]# ls
data.file  x000  x001  x002  x003  x004  x005  x006  x007  x008  x009  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj
//除了k,还可以使用M (MB)、c (GB)、c (byte)、w (word)[root@localhost ~]# split -b 10k data.file -d -a 3 split_file ## 修改前缀名字
[root@localhost ~]# ls
data.file  split_file000  split_file001  split_file002  split_file003  split_file004  split_file005  split_file006  split_file007  split_file008  split_file009[root@localhost ~]# split -8 /etc/passwd   ##按行切割
[root@localhost ~]# ls
data.file  xaa  xab  xac
[root@localhost ~]# cat xa
xaa  xab  xac
[root@localhost ~]# cat xaa
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:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt[root@localhost ~]# rm -f x*
[root@localhost ~]# split -l 8 /etc/passwd    ##l可省略
[root@localhost ~]# ls
data.file  xaa  xab  xac
[root@localhost ~]# cat xaa
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:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt

csplit 根据文本特点分割文件

语法参数:csplit [参数]常用参数:
-b<输出格式>或--suffix-format=<输出格式>    预设的输出格式其文件名称为xx00,xx01等,用户可以通过改变<输出格式>来改变输出的文件名
-f<输出字首字符串>或--prefix=<输出字首字符串>     预设的输出字首字符串其文件名为xx00,xx01等,如果制定输出字首字符串为“hello”,则输出的文件名称会变成hello00,hello、01……
-k或--keep-files     保留文件,就算发生错误或中断执行,与不能删除已经输出保存的文件
-n<输出文件名位数>或--digits=<输出文件名位数>     预设的输出文件名位数其文件名称为xx00,xx01……如果用户指定输出文件名位数为“3”,则输出的文件名称会变成xx000,xx001等
-q或-s或--quiet或--silent  不显示指令执行过程
-z或--elide-empty-files  删除长度为0 Byte文件。
[root@localhost ~]# cat server.log
SERVER一1
[connection] 192.168.0.1 success
[connection] 192.168.0.2 failed
[diaconnect] 192.168.0.3 pending
[connection] 192.168.0.4 success
SERVER-2
[connection] 192.168.0.1 failed
[connection] 192.168.0.2 fai1ed
[disconnect] 192.168.0.3 success
[connection] 192.168.0.4 failed[root@localhost ~]# csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log" ; rm -f server00.log
[root@localhost ~]# ls
data.file  server01.log  server02.log  server.log
[root@localhost ~]# cat server01.log
SERVER一1
[connection] 192.168.0.1 success
[connection] 192.168.0.2 failed
[diaconnect] 192.168.0.3 pending
[connection] 192.168.0.4 success
[root@localhost ~]# cat server02.log
SERVER-2
[connection] 192.168.0.1 failed
[connection] 192.168.0.2 fai1ed
[disconnect] 192.168.0.3 success
[connection] 192.168.0.4 failed/SERVER/用来匹配某一行,分割过程即从此处开始。
/[REGEX]/表示文本样式。包括从当前行(第一行)直到(但不包括)包含“SERVER"的匹配行。
{*}表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。
-s使命令进入静默模式,不打印其他信息。
-n指定分割后的文件名后缀的数字个数,例如01、02、03等。
-f指定分割后的文件名前缀(在上面的例子中,server就是前缀)。
-b指定后缀格式。例如“%02d.log”,类似于C语言中printf的参数格式。在这里文件名=前缀+后缀=server + %02d.log。
因为分割后的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删掉分割的第一行也就是server00.log

根据扩展名提取文件名

有一些脚本是依据文件名进行各种处理的。我们可能会需要在保留扩展名的同时修改文件名、转换文件格式(保留文件名的同时修改扩展名)或提取部分文件名。shell具有的内建功能可以依据不同的情况来切分文件名。

##提取名称
[root@localhost ~]# file_jpg="sample.jpg"
[root@localhost ~]# name=${file_jpg%.*}
[root@localhost ~]# echo file name is $name
file name is sample${VAR%.*〕的含义是:
从$VARIABLE中删除位于%右侧的通配符(在前例中是.*)所匹配的字符串。通配符从右向左进行匹配。
给VAR赋值,VAR=sample.jpg。那么,通配符从右向左就会匹配到.jpg,因此,从$VAR中删除匹配结果,就会得到输出“sarnple”。%属于非贪婪操作,他找出从右到左匹配通配符的最短结果
%%属于贪婪操作, 他会找出符合条件的最长字符串
例如:
[root@localhost ~]# var=123.abc.256.789.txt
[root@localhost ~]# echo ${var%%.*}
123
[root@localhost ~]# echo ${var%.*}
123.abc.256.789
##提取扩展名
[root@localhost ~]# extension=${file_jpg#*.}
[root@localhost ~]# echo $extension
jpg#与%类似只是顺序相反。
#是从左往右进行匹配[root@localhost ~]# var=123.abc.256.789.txt
[root@localhost ~]# echo ${var#*.}
abc.256.789.txt
[root@localhost ~]# echo ${var##*.}
txt
//当文件有多个扩展名的时候,使用##贪婪匹配能更准确的提取出扩展名

批量重命名与移动

[root@localhost ~]# cat rename.sh
#!/bin/bash
#文件名rename.sh
count=1;
for img in *.log
do
new=image-$count.${img##*.}mv "$img" "$new" 2> /dev/nullif [ $? -eq 0 ];thenecho "Renaming $img to $new"
let count++fi
done[root@localhost ~]# ls
data.file  rename.sh  server01.log  server02.log  server.log[root@localhost ~]# ./rename.sh
Renaming server01.log to image-1.log
Renaming server02.log to image-2.log
Renaming server.log to image-3.log

交互输入自动化

##简单交互
[root@localhost ~]# cat test.sh
#!/bin/bashread -p "你想打印什么?" print1echo $print1
[root@localhost ~]# chmod +x test.sh
[root@localhost ~]# ./test.sh
你想打印什么?123
123

read 从标准输入中读取数值

read命令的功能是用于读取单行数据内容,一般是从标准输入中读取数值,用于给变量赋值。

语法格式:read [参数]常用参数:
-a  定义一个数组,以空格为间隔符进行赋值
-d  定义一个结束标志
-p  设置提示信息
-e  在输入的时候可以使用命令补全功能
-n  定义输入文本的长度
-r  禁用转义符(\)
-s  输入字符不在屏幕显示
-t  限定最长等待时间
-u  从文件描述符中读入信息
##简单交互自动化 \n等于回车
[root@localhost ~]# echo -e  "123\n" | ./test.sh
123##简单升级一下
[root@localhost ~]# cat test.sh
#!/bin/bashread -p "你想打印什么?" print1
read -p "你还想打印什么?" print2
echo $print1
echo $print2
[root@localhost ~]# ./test.sh
你想打印什么?234
你还想打印什么?567
234
567[root@localhost ~]# echo -e  "123\nabc\n" | ./test.sh
123
abc##输入较多时可以制作输入文件
[root@localhost ~]# echo -e  "cvb\n789\n"  > input.txt
[root@localhost ~]# cat input.txt
cvb
789[root@localhost ~]# ./test.sh < input.txt
cvb
789

除此之外还可以使用一些函数例如expect

文件管理

UNIX将操作系统中的一切都视为文件。文件与每一个操作息息相关,而我们可以利用它们进行各种与系统或进程相关的处理工作。例如,我们所使用的命令终端就是和一个设备文件关联在一起的。

有各种不同形式的文件,比如目录、普通文件、块设备、字符设备、符号链接、套接字和命名管道等。

文件的属性包括文件名、大小、文件类型、文件内容修改时间(modification time)、文件访问时间(access time)、文件属性更改时间(change time)、i节点、链接以及文件所在的文件系统

生成任意大小的文件

创建特定文件最简单的办法就是使用dd命令,此法在上文分割文件也提到过,在此详细介绍一下。

##if代表输入文件,of代表输出文件,bs指定大小,count指定块
[root@localhost ~]# dd if=/dev/zero of=junk.data bs=1M count=1
记录了1+0 的读入
记录了1+0 的写出
1048576字节(1.0 MB)已复制,0.00126048 秒,832 MB/秒
[root@localhost ~]# du -sh junk.data
1.0M    junk.data
/// /dev/zero是一个字符设备,它会不断返回0值字节。

如果不指定输入参数(if),默认情况下dd会从stdin中读取输入。与之类似,如果不指定输出参数(of),则dd会将stdout作为默认输出。

文本文件的交集与差集

comm 比较差异

comm命令可用于两个文件之间的比较。它有很多不错的选项可用来调整输出,以便我们执行交集、求差(difference)以及差集操作。

  • 交集:打印出两个文件所共有的行。
  • 求差:打印出指定文件所包含的且不相同的那些行。
  • 差集:打印出包含在文件A中,但不包含在其他指定文件中的那些行。
[root@localhost ~]# cat A.txt
apple
orange
gold
silver
steel
[root@localhost ~]# cat B.txt
orange
gold
cookies
carrot
[root@localhost ~]# comm A.txt B.txt  //comm必须使用排过序的文件作为输入
appleorange
comm: 文件1 没有被正确排序
comm: 文件2 没有被正确排序goldcookiescarrot
silver
steel
[root@localhost ~]# sort A.txt -o A.txt ;sort B.txt -o B.txt
//-o 将排过序结果输入指定文件
[root@localhost ~]# comm A.txt B.txt
applecarrotcookiesgoldorange
silver
steel
##输出的第一列包含只在A.txt中出现的行,第二列包含只在B.txt中出现的行,第三列包含A.txt和B.txt中相同的行。各列以制表符(t)作为定界符。

有一些选项可以按照我们的需求进行格式化输出,
例如:
-1 从输出中删除第一列
-2 从输出中删除第二列
-3 从输出中删除第三列

//删除第一,二列,便只会打印出他们的交集
[root@localhost ~]# comm A.txt B.txt -1 -2
gold
orange//取出全集,并删除制表符转化为单列
[root@localhost ~]# comm A.txt B.txt -3 | sed 's/^\t//'
apple
carrot
cookies
silver
steel

查找并删除重复文件

此处的重复文件指内容一样的文件,而不是名字相同的文件。
在前面校验和里面提到过,相同的文件内容的校验和也是相同的。

##创建测试文件及副本
[root@localhost ~]# echo "hello"  > test ; cp test test_copy1 ; cp test test_copy2;
[root@localhost ~]# echo "next" > other[root@localhost ~]# vim remove.sh
#!/ bin/ bash
#文件名:remove_duplicates.sh
#用途:查找并删除重复文件,每一个文件只保留一个样本
ls -lS | awk "BEGIN {
getline;getline;
name1=$8 ; size=$5
}
{name2=$8 ;
if (size==$5)
{
"md5sum "name1 | getline; csum1=$1;
"md5sum "name2 | getline; csum2=$1;
if ( csum1==csum2 )
{print name1 ; print name2 }};
size=$5; name1=name2 ;
}'| sort -u > duplicate_files
cat duplicate_files | xargs -I { } md5sum { } | sort | uniq -w 32 | awk '{ print "^"$2"$" }'| sort -u > duplicate_sample
echo Removing . .
comm duplicate.files duplicate_sample -2 -3 | tee /dev/stderr | xargs rm
echo Removed duplicates files successfully.

创建不可删除文件

[root@localhost ~]# cat /etc/mtab
rootfs / rootfs rw 0 0
sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=6058616k,nr_inodes=1514654,mode=755 0 0
securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev/shm tmpfs rw,seclabel,nosuid,nodev 0 0
.....
#可以查看分区设备路径与文件系统类型

chattr 修改文件属性

不可修改属性是保护文件不被修改的安全手段之一。最有代表性的例子就是/etc/shadow文件。该文件由当前系统中所有用户的加密密码组成。我们通过密码才能够登录系统。用户通常用passwd命令修改自己的密码。执行passwd时,它实际上就修改了letc/shadow文件。我们可以将shadow文件设置为不可修改,这样就再没有用户能够修改密码了。

[root@localhost ~]# useradd test
[root@localhost ~]# passwd test
更改用户 test 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符  ##不影响修改
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[root@localhost ~]# chattr +i /etc/shadow  ##添加不可修改属性
[root@localhost ~]# passwd test
更改用户 test 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd: 鉴定令牌操作错误
[root@localhost ~]# echo '12345' | passwd --stdin test
更改用户 test 的密码 。
passwd: 鉴定令牌操作错误
[root@localhost ~]# chattr -i /etc/shadow   ##移除不可修改属性
[root@localhost ~]# echo '12345' | passwd --stdin test
更改用户 test 的密码 。
passwd:所有的身份验证令牌已经成功更新。
//移除不可修改属性后,可以正常修改

批量生成空白文件

touch 创建文件

touch命令的功能是用于创建空文件与修改时间戳。如果文件不存在,则会创建出一个空内容的文本文件;如果文件已经存在,则会对文件的Atime(访问时间)和Ctime(修改时间)进行修改操作,管理员可以完成此项工作,而普通用户只能管理主机的文件。

语法格式:touch [参数] 文件常用参数:
-a  改变档案的读取时间记录
-m  改变档案的修改时间记录
-r  使用参考档的时间记录,与 --file 的效果一样
-c  不创建新文件
-d  设定时间与日期,可以使用各种不同的格式
-t  设定档案的时间记录,格式与 date 命令相同
--no-create     不创建新文件
--help  显示帮助信息
--version   列出版本讯息
#1
[root@localhost test1]# touch {1..100}.py
[root@localhost test1]# ls
100.py  13.py  17.py  20.py  24.py  28.py  31.py  35.py  39.py  42.py  46.py  4.py   53.py  57.py  60.py  64.py  68.py  71.py  75.py  79.py  82.py  86.py  8.py   93.py  97.py
10.py   14.py  18.py  21.py  25.py  29.py  32.py  36.py  3.py   43.py  47.py  50.py  54.py  58.py  61.py  65.py  69.py  72.py  76.py  7.py   83.py  87.py  90.py  94.py  98.py
11.py   15.py  19.py  22.py  26.py  2.py   33.py  37.py  40.py  44.py  48.py  51.py  55.py  59.py  62.py  66.py  6.py   73.py  77.py  80.py  84.py  88.py  91.py  95.py  99.py
12.py   16.py  1.py   23.py  27.py  30.py  34.py  38.py  41.py  45.py  49.py  52.py  56.py  5.py   63.py  67.py  70.py  74.py  78.py  81.py  85.py  89.py  92.py  96.py  9.py
#2
[root@localhost test1]# for i in {1..10}.php; do touch $i; done
[root@localhost test1]# ls
10.php  1.php  2.php  3.php  4.php  5.php  6.php  7.php  8.php  9.php

列举文件类型统计信息

file 识别文件类型

ile命令的功能是用于识别文件的类型,也可以用来辨别一些内容的编码格式。由于Linux系统并不是像Windows系统那样通过扩展名来定义文件类型,因此用户无法直接通过文件名来进行分辨。file命令则是为了解决此问题,通过分析文件头部信息中的标识来显示文件类型,使用很方便。

语法格式:file [参数] 文件常用参数:
-b  列出辨识结果时,不显示文件名称 (简要模式)
-c  详细显示指令执行过程
-f  指定名称文件,显示多个文件类型信息
-L  直接显示符号连接所指向的文件类别
-m  指定魔法数字文件
-v  显示版本信息
-z  尝试去解读压缩文件的内容
-i  显示MIME类别
[root@localhost ~]# file test
test: ASCII text
[root@localhost ~]# file -i test
test: text/plain; charset=us-ascii[root@localhost ~]# cat filestat.sh
#!/bin/bash
#文件名: filestat.sh
if [ $# -ne 1 ];then  echo $0 basepath;echo
fi
path=$1declare -A statarray;
while read line;
doftype=`file -b "$line"`let statarray["$ftype"]++;
done< <( find $path -type f -print)for ftype in "${!statarray[@]}";
doecho $ftype : ${statarray["$ftype"]}
done[root@localhost ~]# ./filestat.sh test
ASCII text : 1
[root@localhost ~]# ./filestat.sh test1
empty : 10

在脚本中声明了一个关联数组statarray,这样可以用文件类型作为数组索引,将每种文件类型的数量存入数组。每次遇到一个文件类型,就用1et增加计数。find命令以递归的方式获取文件路径列表。脚本中的ftype='file -b "$line"使用file命令获得文件类型信息。

<(find $path -type f -print)等同于文件名。只不过它用子进程输出来代替文件名。注意这里还有另外一个<。
${ !statarray [@]}用于返回一个数组索引列表。

shell脚本耕升(一)相关推荐

  1. jar包部署shell脚本编写,在服务器上部署jar包,在Linux服务器上部署服务,设置编码格式,设置内存管理

    准备步骤: 1.安装java环境,知道java安装目录 2.将jar包拖放或发送至服务器中(目录自定义) 一.编写shell脚本,将以下代码放在shell脚本中,将shell脚本放在jar包同级目录下 ...

  2. 快速给shell脚本加上使用提示

    我们只需通过在shell脚本前面加上如下的代码即可: #!/bin/bash ### ### my-script - does one thing well ### ### Usage: ### my ...

  3. Ubuntu系统执行shell 脚本的方法

    使用前了解 Shell: Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁 Shell: Shell 脚本(shell script),是一种为 shell 编写的脚本程序. 下面 ...

  4. Windows 系统执行Shell 脚本的方法

    使用前了解 Shell: Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁 Shell: Shell 脚本(shell script),是一种为 shell 编写的脚本程序. 下面 ...

  5. shell监控java接口服务_Linux系统下Java通过shell脚本监控重启服务

    简介 最近运维人员提出需求,增加一个运维页面, 查询当前的业务进程信息包括:进程名称.启动命令.启动时间.运行时间等,可以通过页面点击重启按钮,可以重启后端的一系列系统进程. 思路 java程序获取l ...

  6. linux 脚本 alias,在shell脚本中使用alias别名

    本文最后更新于2015年7月12日,已超过 1 年没有更新,如果文章内容失效,还请反馈给我,谢谢! 缘由: 经常用Linux进行操作的同学一般都会有各种各样的技巧来提升工作效率,而添加/改写shell ...

  7. linux shell脚本攻略_(python)Linux下shell脚本监控Tomcat的状态并实现自动启动步骤...

    今天为大家带来的内容是:(python)Linux下shell脚本监控Tomcat的状态并实现自动启动步骤 本文内容主要介绍了Linux下shell脚本监控Tomcat的状态并实现自动启动的步骤,文章 ...

  8. linux重启sh脚本,Linux 之shell脚本系列之服务启动/关闭/重启/状态

    一 问题 自己开发的程序,如何用shell 脚本实现 启动,关闭,重启,查看状态? 二 方案 myshell.sh #!/bin/sh SERVICE="fm_tuoguan_shell&q ...

  9. linux按文件名排序ls,linux – 如何使用shell脚本按名称对文件进行排序

    我想用 Shell脚本按日期排序所有文件. 例如,在/ Users / KanZ / Desktop / Project / Test /中有文件M1.h,A2.h和F4.h. 每个文件都有不同的时间 ...

最新文章

  1. php 做的网页 排版错误,discuz 帖子排版显示出错
  2. 关于计算机专业的求职信英文怎么说,计算机求职信范文英文3篇
  3. 【渝粤教育】电大中专Office办公软件 (4)作业 题库
  4. 前端学习(1840):前端面试题之mpvue和小程序
  5. mysql重要的监控参数_zabbix3.0.2使用percona mysql插件来监控mysql5.7   以及必须监控的性能参数...
  6. 春招冷淡,跳槽无望?
  7. CCNP-冗余链路中的广播风暴、多帧复制、地址表的不稳定
  8. Excel函数,数据透视表图,某招聘网站职位分析项目
  9. word中快速确认字体颜色的方法
  10. Microsoft To-Do List 、Mac Reminders 与OmniFocus相互同步方法及AppleScript脚本
  11. 新手学习python零基础_一个零基础新手学习Python应该知道的学习步骤与规划
  12. ORACLE怎么读英语,oracle是什么意思_oracle怎么读_oracle翻译_用法_发音_词组_同反义词_神示所-新东方在线英语词典...
  13. 蒙特卡洛模拟与matlab,用MATLAB进行蒙特卡洛模拟?
  14. 时序预测 | MATLAB实现BiLSTM时间序列未来多步预测
  15. 5.3 用户注册与登录
  16. TOS和DSCP总结
  17. 远程计算机不接受连接 smb,该设备或资源(192.168.1.100)未设置为接受端口“文件和打印机共享(SMB)̶ - Microsoft Community...
  18. 计算机中丢失msctfmonitor,电脑没了输入法怎么办win7
  19. xp系统关闭文件和打印共享服务器,XP打印共享四大问题及解决方法
  20. 腾讯微博平台开发,熟悉API结构,获得头像本地保存

热门文章

  1. csdn上传资源中断
  2. 音视频云系列 - 谈谈XR关键技术及VR/AR/MR/XR关系
  3. Galera Cluster :一种新型的高一致性MySql集群框架
  4. 【记录一次硬盘修复过程】
  5. Java基础学习记录(三)
  6. Windows提权工具 CVE-2019-1405 CVE-2019-1322
  7. 大疆A板STM32427用CAN通信进行M2006/M3508位置闭环和往复转动
  8. 我的前端学习之路<定位>
  9. linux swap分区修复,(解决后追加50分)linux top 可以看到swap分区, df -h又看不到,这样的结果是否正常?...
  10. STM32外部中断库函数操作