03内容格式化

93 阅读15分钟

内容格式化

常用符号解读

信息传递

重定向

在shell脚本中有两类常见的重定向符号:

  1. 覆盖式重定向,> 表示将符号左侧的内容,以覆盖的方式输入到右侧文件中;< 表示将符号右侧的内容,以覆盖的方式输入到左侧文件中
  2. 追加式重定向,>> 表示将符号左侧的内容,以追加的方式输入到右侧文件的末尾行中;<< 表示将符号右侧的内容,以追加的方式输入到左侧文件的末尾行中
# 覆盖式重定向
echo nihao > file.txt

cat file.txt
nihao

# 使用重定向符号给文件中增加内容
echo "file1.txt" > file.txt

cat file.txt
file1.txt

# 追加式重定向
# 使用重定向符号给文件中增加内容
echo "file2.txt" >> file.txt

cat file.txt
file1.txt
file2.txt

管道符

|这个就是管道符,常用于将两个命令隔开,然后命令间(从左向右)传递信息使用的

使用格式,命令1 | 命令2,管道符左侧命令1 执行后的结果,传递给管道符右侧的命令2使用

# 查看当前系统中的全局变量SHELL
env | grep SHELL
SHELL=/bin/bash

终端输出

后台执行

&就是将一个命令从前台转到后台执行,使用格式如下:命令 &

# 前台执行休眠命令,界面卡住4秒后消失
sleep 4

# 后台执行休眠命令
sleep 10 &
[1] 3522

ps aux | grep sleep
root       3522  0.0  0.0 108052   360 pts/1    S    15:08   0:00 sleep 10
root       3524  0.0  0.0 112808   972 pts/1    S+   15:08   0:00 grep --color=auto sleep

信息符号

  • 1 表示正确输出的信息
  • 2 表示错误输出的信息
  • 2>&1 代表所有输出的信息,也可以简写为 "&>"
# 标准正确输出重定向到zhengque文件
cat file.txt 1>> zhengque

cat zhengque
file1.txt
file2.txt

# 标准错误输出重定向到errfile文件
dsfadsfadsfa 2>> errfile

cat errfile
-bash: dsfadsfadsfa: command not found

cat > ceshi.sh << "EOF"
#!/bin/bash
# 输出正确信息
echo '下一条错误命令'
# 执行错误命令,输出错误信息
dsfsafsafdsa
EOF

/bin/bash ceshi.sh
下一条错误命令
ceshi.sh: line 5: dsfsafsafdsa: command not found

/bin/bash ceshi.sh 1>> ceshi-ok 2>> ceshi-err

cat ceshi-ok
下一条错误命令

cat ceshi-err
ceshi.sh: line 5: dsfsafsafdsa: command not found

/bin/bash ceshi.sh >> ceshi-all 2>&1

cat ceshi-all
下一条错误命令
ceshi.sh: line 5: dsfsafsafdsa: command not found

rm -f file.txt zhengque errfile ceshi*

输入格式化

EOF原理

场景需求:在运维岗位中,有非常多的场景需要我们在脚本中编写应用软件的配置文件。在这些应用软件的配置文件中,经常携带大量的格式,尤其是携带空格的层级格式,如果我们一个一个的编写好标准的配置文件,但是一旦涉及到场景信息的动态化调整,固定好的配置文件就不太适合了,所以我们需要一种方法能够实现整个动态的格式化需求

解决方法:在shell编程中,"EOF”通常与"<<”结合使用,"<<EOF”表示后续的输入作为子命令或子shell的输入,直到遇到"EOF”,再次返回到主调用shell,可将其理解为分界符(delimiter)。所谓的 EOF,就是End of file的缩写,它是一种自定义的文件内容终止符。既然是分界符,那么形式自然不是固定的,这里可以将”EOF"可以进行自定义,但是前后的”EOF"必须成对出现且不能和shell命令冲突。第一个EOF如果用双引号引起来,这样EOF之间的内容则被当成纯字符串不会被提前解析,否则会提前解析里面的内容(例如解析变量)

语法格式

交互式程序 << EOF
command1
command2
...
EOF

注意:最后的"EOF"必须单独占一行,而且必须顶格写,如果不想受到如此限制的话,使用<<-符号。<<- 的作用是自动去除最后一个EOF前面的制表符\t【注意,对于空格无效】。前后两个EOF可以是任意一个字符,比如aaa,只要前后两个边界内容一致即可。

"EOF"中间的内容将以标准输入的形式输入到”交互式程序",当shell看到”<<"知道其后面输入的分界符,当shell再次看到分界符时,两个分界符中间的部分将作为标准输入。

# 终端方式接收多行信息,然后交给一个命令
cat << EOF
> Dear Wang:
>   jian dao ni hen gaoxing.
> danshi wo bu xihuan ni.
> zaijian.
>                zhaoliu
>                2100-11-11
> EOF
Dear Wang:
  jian dao ni hen gaoxing.
danshi wo bu xihuan ni.
zaijian.
               zhaoliu
               2100-11-11

脚本中实践EOF

编写请假条脚本qingjiatiao.sh,内容如下

#!/bin/bash
# EOF演示请假条示例

cat << EOF
                        请假条
王老师:
    我因患急性空腹病,现在需要到火锅理疗,不能到学校上课,
请准假一天。恳请批准!
                                             请假人:李四
                                                 6月1日
EOF
# 执行脚本示例
/bin/bash qingjiatiao.sh
                        请假条
王老师:
    我因患急性空腹病,现在需要到火锅理疗,不能到学校上课,
请准假一天。恳请批准!
                                             请假人:李四
                                                 6月1日
# 末尾EOF前面有制表符
sed -i '$ s/EOF/\tEOF/' qingjiatiao.sh

# 执行脚本后效果
/bin/bash qingjiatiao.sh
qingjiatiao.sh: line 11: warning: here-document at line 4 delimited by end-of-file (wanted `EOF')

# 将<< 替换为 <<-
sed -i 's/<</<<-/' qingjiatiao.sh

# 脚本执行后的效果
/bin/bash qingjiatiao.sh
                        请假条
王老师:
    我因患急性空腹病,现在需要到火锅理疗,不能到学校上课,
请准假一天。恳请批准!
                                             请假人:李四
                                                 6月1日

rm -f qingjiatiao.sh

文本输入

cat实践

# 实现多行文件的输入
cat > file  << EOF
...
EOF

# 定制主机解析名信息
cat >> hosts << EOF
10.0.0.13 k8s-master
10.0.0.14 k8s-node1
10.0.0.15 k8s-node2
EOF

cat hosts
10.0.0.13 k8s-master
10.0.0.14 k8s-node1
10.0.0.15 k8s-node2

定制nginx配置文件的脚本define-nginx-conf.sh,内容如下

#!/bin/bash
# 定制nginx的配置文件

# 定制配置文件目录
NGINX_DIR='/data/server/conf'
NGINX_CONF='nginx.conf'

# 创建基本目录
mkdir -p $NGINX_DIR

# 定制nginx配置文件
cat > $NGINX_DIR/$NGINX_CONF << EOF
server {
  listen 80;
  server_name www.example.com
  listen / {
     proxy_pass http://10.0.0.12:10086;
  }
}
EOF
# 执行文件后的效果
/bin/bash define-nginx-conf.sh

cat /data/server/conf/nginx.conf
server {
  listen 80;
  server_name www.example.com
  listen / {
     proxy_pass http://10.0.0.12:10086;
  }
}

rm -rf /data/server
rm -f hosts define-nginx-conf.sh

tee实践

tee命令读取标准输入,把这些内容同时输出到标准输出和(多个)文件中,tee命令可以重定向标准输出到多个文件。要注意的是:在使用管道符时,前一个命令的标准错误输出不会被tee读取

命令格式

  • 样式1,只输出到标准输出,tee
  • 样式2,输出到标准输出的同时,保存到文件file中,tee file
  • 样式3,输出到标准输出的同时,追加到文件file中。如果文件不存在则创建;如果文件存在则追加。tee -a file, tee host2 <<- EOF ... EOF
  • 样式4,输出到标准输出两次,tee -
  • 样式5,输出到标准输出两次,同时保存到file1和file2中,tee file1 file2 -
# 实践1 - 仅输出到当前屏幕
echo tee-test | tee

# 实践2 - 同时输出到屏幕和文件
echo tee-test | tee tee-file

cat tee-file
tee-test

# 实践3 - 追加到对应的文件中
echo tee-test1 | tee tee-file

cat tee-file
tee-test1

echo tee-test2 | tee -a tee-file

cat tee-file
tee-test1
tee-test2

# 实践4 - 输出多次信息
echo tee-test | tee
tee-test

echo tee-test | tee -
tee-test
tee-test

echo tee-test | tee - -
tee-test
tee-test
tee-test

echo tee-test | tee - - -
tee-test
tee-test
tee-test
tee-test

# 实践5 - 保存到多个文件
echo tee-test | tee file-1 file-2 file-3

cat file-1
tee-test

cat file-2
tee-test

cat file-3
tee-test

# 实践6 - 接收命令行多行信息,同时在文件和当前终端显示
tee host2 << EOF
> 10.0.0.13 k8s-master
> 10.0.0.14 k8s-node1
> 10.0.0.15 k8s-node2
> EOF
10.0.0.13 k8s-master
10.0.0.14 k8s-node1
10.0.0.15 k8s-node2

cat host2
10.0.0.13 k8s-master
10.0.0.14 k8s-node1
10.0.0.15 k8s-node2

rm -f tee-file host2 file-*

案例实践 - kubernetes参数配置

# 定制kubernetes的网络模块加载,将EOF中间的内容重定向为tee的标准输入
cat << EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
br_netfilter

# 定制kubernetes的数据包内核参数
cat << EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

sysctl --system

rm -f /etc/modules-load.d/k8s.conf /etc/sysctl.d/k8s.conf

输出格式化

echo解读

echo [SHORT-OPTION]... [STRING]...echo命令的功能是将内容输出到默认显示设备,一般起到一个提示的作用

选项说明
-n不要在最后自动换行
-e启用反斜杠转义的解释
-E禁用反斜杠转义的解释(默认)

如果-e生效,则识别以下转义字符

转义字符说明
\\反斜杠字符
\a发出警告声
\b删除前一个字符
\c最后不加上换行符号
\e可以用于设置颜色
\f换行但光标仍旧停留在原来的位置,换页(formfeed)
\n换行且光标移至行首
\r光标移至行首,但不换行
\t水平制表符
\v垂直制表符
\0NNN打印NNN(八进制)所代表的ASCII字符
\xHH打印NN(十六进制)所代表的ASCII字符
# 信息的输出
# echo后边用单引号包围要添加的内容
echo 'hello world' > hello.txt

cat hello.txt
hello world

# 引号信息输出
echo "I'm a king of the world."
I'm a king of the world.

# 特殊符号的输出
# 使用 -e 选项启用转义字符的解析
echo -e "The 2021 State of DevOps Report\n\t- is here"
The 2021 State of DevOps Report
        - is here

# 内容的拼接
# 使用 -n 选项启用信息输出不换行
echo -n hello;echo world
helloworld

rm -f hello.txt

字体颜色

场景需求

echo本质上是将信息内容输出到当前的屏幕终端,如果只是一种颜色的话,可能导致视觉疲劳。所以,一般情况下,我们在显示信息的时候,往往会通过颜色的方式实现特定内容的颜色高亮显示。echo命令可以修改字体类型,字体背景色以及字体颜色,转义序列\033可以用于改变字体属性

格式解读

# 格式如下:echo -e "\033[字背景颜色;文字颜色m字符串\033[0m"
echo -e "\033[41;36m 显示的内容 \033[0m"

image.png

颜色分类

色彩绿
字体色3031323334353637
背景色4041424344454647

结束控制符

最后面控制选项说明 \033[0m 关闭所有属性 \033[1m 设置高亮度 \033[4m 下划线 \033[5m 闪烁  \033[7m 反显 \033[8m 消隐 注意: \033 是八进制的ESCAPE字符,我们可以用 \e 来代替

最常用的是字体颜色红绿蓝(31,32,33)、开始符号\033[、分隔符m、结束符\033[0m

# 字体颜色示例
echo -e "\033[30m 黑色字 \033[31m 红色字 \033[32m 绿色字 \033[33m 黄色字 \033[0m"
echo -e "\033[34m 蓝色字 \033[35m 紫色字 \033[36m 天蓝字 \033[37m 白色字 \033[0m"

# 背景颜色示例
echo -e "\033[40;37m 黑底白字 \033[41;37m 红底白字 \033[42;37m 绿底白字 \033[0m"
echo -e "\033[43;37m 黄底白字 \033[44;37m 蓝底白字 \033[45;37m 紫底白字 \033[0m"
echo -e "\033[46;37m 天蓝底白字 \033[47;30m 白底黑字 \033[0m"

image.png

信息颜色显示

# 定制堡垒机的测试页面脚本
cat > simple_jumpserver.sh << "EOF"
#!/bin/bash
# 功能:定制堡垒机的展示页面
# 作者:zhang
# 版本:V0.1
# 联系:zhang.com

echo -e "\e[31m \t\t 欢迎使用堡垒机"

echo -e "\e[32m
-----------请选择你要登录的远程主机-----------
 1: 10.0.0.14 (nginx)
 2: 10.0.0.15 (tomcat)
 3: 10.0.0.19 (apache)
 q: 使用本地主机
----------------------------------------------
"'\033[0m'
echo -e "请输入您要选择的远程主机编号: "
EOF

/bin/bash simple_jumpserver.sh

image.png

rm -f simple_jumpserver.sh

printf格式化

场景需求

虽然我们能够通过echo的方式实现信息某种程度的格式化输出,但是很多信息的输出偏重于手工的干预,效率太慢。我们需要一种功能更强大、效率更高的格式化手段

printf简介

printf 命令模仿 C 程序库(library)里的 printf() 程序。由于 printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以指定字符串的宽度、左右对齐方式等。默认 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n

基本语法

printf [-v var] format [arguments], -v var表示将输出赋值给shell变量VAR,而不是显示在标准输出上

image.png

格式化替换符说明
%s字符串
%d,%i十进制整数
%f浮点格式,默认展示小数点后6位,可以通过%.2f(表示小数点后2位)这种格式指定展示小数点后几位
%cASCII字符,即显示对应参数的第一个字符
%b相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义
%o八进制值
%u不带正负号的十进制值
%x十六进制值(a-f)
%X十六进制值(A-F)
%%表示%本身
格式化转义符号说明
\"双引号
\\一个字面上的反斜杠字符
\a警告字符,通常为ASCII的BEL字符
\b后退
\c抑制(不显示)输出结果中任何结尾的换行字符
\e可以用于设置颜色
\f换页(formfeed)
\n换行
\r回车(Carriage return)
\t水平制表符
\v垂直制表符
\NNN八进制NNN字节(1到3位数字)
\xHH十六进制HH字节(1 ~ 2位)
\uHHHHUnicode (ISO/IEC 10646)字符,十六进制值为HHHH(4位数字)
\UHHHHHHHH十六进制值为HHHHHHHH的Unicode字符(8位)

格式化字符解释

  • - 将字段里已格式化的值向左对齐
  • 空格 在正值前置一个空格,在负值前置一个负号
  • + 总是在数值之前放置一个正号或负号,即便是正值也是
  • # 下列形式选择其一
    • %o有一个前置的o;%x与%X分别前置的0x与0X
    • %e,%E与%f总是在结果中有一个小数点;%g与%G为没有结尾的零
  • 0 以零填补输出,而非空白,这仅发生在字段宽度大于转换后的情况
  • 格式化时%后面可以添加一个数字,表示列宽,默认是右对齐,再添加一个减号表示左对齐;格式化整数时,还可以在列宽前面加个0表示用零填补输出,默认是空白(只有右对齐时才可以补0,左对齐时不会,因为这样会引起歧义)

简单实践

# 实践1 - 命令演示

# 普通echo命令演示换行信息和非换行信息
echo "Hello, Shell Base"
echo -n "Hello, Shell Base"

# printf命令演示换行信息和非换行信息
printf "Hello, Shell Base\n"
printf "Hello, Shell Base"

# 实践2 - 替换符号演示

# 基本信息演示 - 单引号和双引号效果一样
# 注意:相关信息会按照顺序依次替换到格式化的替换符位置
printf "姓名:%s, 语文:%d, 数学:%d\n" "张三" 89 98
姓名:张三, 语文:89, 数学:98

printf '姓名:%s, 语文:%d, 数学:%d\n' "张三" 89 98
姓名:张三, 语文:89, 数学:98

# 数字格式展示
# 注意:通过 %.nf,n代表小数点后面的可显示的位数
printf '姓名:%s, 身高:%f米, 体重:%f公斤\n' "张三" 1.7 66
姓名:张三, 身高:1.700000米, 体重:66.000000公斤

printf '姓名:%s, 身高:%.2f米, 体重:%.1f公斤\n' "张三" 1.7 66
姓名:张三, 身高:1.70米, 体重:66.0公斤

# 实践3 - 简单格式化

# () 用于信息的批量化显示
printf "(%d %s)\n" 1 张三 2 李四 3 王五
(1 张三)
(2 李四)
(3 王五)

# printf默认不携带最后的换行
printf "(%d %s)  " 1 张三 2 李四 3 王五
(1 张三)  (2 李四)  (3 王五) 

# 借助于echo的功能实现换行的效果
printf "(%d %s)  " 1 张三 2 李四 3 王五; echo
(1 张三)  (2 李四)  (3 王五)

# 实践4 - 格式化补充

# %s字符串格式化,注意:%-10s,代表信息后面携带10个空格(不加-是前面携带10个空格),便于格式化
printf '姓名:%-10s语文:%d, 数学:%d\n' "张三" 89 98 "李四" 87 97
姓名:张三    语文:89, 数学:98
姓名:李四    语文:87, 数学:97

# %d数字格式补全,注意:0的作用就是不用空格补全,而是用0填充,实现格式化
printf "%5d %s\n" 1 张三
    1 张三

printf "%05d %s\n" 1 张三
00001 张三

printf "%05d %s\n" 100 张四
00100 张四

# 实践5 - 环境变量的使用

# 定制环境变量
VAR1=hello; VAR2=shell
# 颜色显示
printf "\033[32m%s \033[31m%s\033[0m\n" $VAR1 $VAR2
hello shell

综合案例

这一节,我们从 java部署、脚本定制,两个方面来学习

java部署

# 创建目录
mkdir /data/{softs,server} -p
cd /data/softs
# 下载java或者上传java
wget https://builds.openlogic.com/downloadJDK/openlogic-openjdk/8u392-b08/openlogic-openjdk-8u392-b08-linux-x64.tar.gz
tar xf openlogic-openjdk-8u392-b08-linux-x64.tar.gz -C /data/server
cd /data/server/
ln -s openlogic-openjdk-8u392-b08-linux-x64 java

# 配置java环境变量
echo 'export JAVA_HOME=/data/server/java' >> /etc/profile.d/java.sh
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> /etc/profile.d/java.sh
source /etc/profile.d/java.sh

# 检查效果
java -version

# 手工清理环境
rm -f /etc/profile.d/java.sh
rm -rf /data/server/java /data/server/openlogic-openjdk-8u392-b08-linux-x64

定制java环境部署脚本

mkdir /data/scripts

/data/scripts/java_install.sh 脚本内容如下

#!/bin/bash
# 功能: java环境的定制
# 版本:v0.1
# 作者:zhang
# 联系:www.zhang.com

# 定制基本信息
JAVA_SOFT='openlogic-openjdk-8u392-b08-linux-x64.tar.gz'
JAVA_DIR='openlogic-openjdk-8u392-b08-linux-x64'
JAVA_NAME='java'
SERVER_HOME='/data/server'
SOFTS_HOME='/data/softs'
RED="echo -e \E[1;31m"
END="\E[0m"

# 安装软件
tar xf $SOFTS_HOME/$JAVA_SOFT -C $SERVER_HOME
ln -s $SERVER_HOME/$JAVA_DIR $SERVER_HOME/$JAVA_NAME

# 定制环境变量
cat > /etc/profile.d/java.sh << EOF
export JAVA_HOME=$SERVER_HOME/$JAVA_NAME
export PATH=\$JAVA_HOME/bin:\$PATH
EOF

# 加载java环境变量文件
source /etc/profile.d/java.sh

# 检查效果
java -version > /tmp/txt 2>&1
java_version=$(grep version /tmp/txt | cut -d '"' -f2)
runtime_version=$(grep Runtime /tmp/txt | cut -d ' ' -f5 | cut -d ")" -f1)
jvm_type=$(grep VM /tmp/txt | cut -d " " -f7)

# 信息显示
$RED---------$JAVA_NAME软件运行情况---------$END
printf "\033[32m%s:\033[33m%s\033[0m\n" "java软件版本" $java_version
printf "\033[32m%s:\033[33m%s\033[0m\n" "java运行时环境版本" $runtime_version
printf "\033[32m%s:\033[33m%s\033[0m\n" "jvm运行模式" $jvm_type
$RED----------------------------------$END
cd /data/scripts

/bin/bash java_install.sh
---------java软件运行情况---------
java软件版本:1.8.0_392-392
java运行时环境版本:1.8.0_392-392-b08
jvm运行模式:mixed
----------------------------------