Linux Shell基线检查高级操作

一、输入解析类

1.1 echo解析tab和换行

问题描述:echo默认是原样输出字符串,并不解析\t和\n等反斜杠字符,如下图所示。我们希望echo能解析\t和\n等字符。

处理办法:可以使用-e指示echo识别反斜杠。

 

1.2 获取给定路径中的上级目录名和文件名

# 给定路径名称。以/etc/passwd为例
path="/etc/passwd"
# 路径对应的上级文件夹名。这里结果为/etc
dir_name=`dirname ${path}`
# 最终目录/文件名。这里结果为passwd
base_name=`basename ${path}`

 

1.3 cat将变量写入文件

问题描述:我们经常需要将变量写到配置文件,比如将java相关的几个变量写到~/.profile,追加多行cat是最方便的但cat默认会在插入时解析变量,如下图所示。我们希望就是原样写入而不自动解析变量。

处理办法:可通过给EOF加上单引号来指示cat不要解析变量。

参考:https://blog.csdn.net/u010154760/article/details/45955797

 

1.4 sed使用变量

我们知道sed的基本格式如下:

# 将test.txt中,匹配matchReg的位置,替换成string
sed -i 's/matchReg/string/g' test.txt

如果matchReg和string部分是确定的那没什么问题,但如果在该部分中我们想使用变量,该如何写呢。答案是将单引号改成双引号:

# 我们以matchReg部分用变量代替作为演示
# sed使用变量的关键就在于将单引号改成双引号
matchReg="anythig"
sed -i "s/${matchReg}/string/g" test.txt

 

1.5 while语句中修改变量值

问题描述:我们知道shell中的变量是全局的,但如果注意会发现有时在while语句内修改变量值并不生效。如下所示,我们想用while语句统计/etc/passwd中的用户数量,但user_count最后依然是0。

user_count=0
cat /etc/passwd | while read line
do
    user_count=`expr $user_count + 1`
done
echo $user_count

处理办法:造成这种情况的原因是while针对数据从管道传输过来这种方式,会启动一个子shell去处理,在子shell中修改参数并不能影响当前shell中的参数的值(相当于函数中的传值)。解决办法是换一种while就在当前shell中处理的写法。

user_count=0
while read line
do
    user_count=`expr $user_count + 1`
done <<< "$(cat /etc/passwd)"
echo $user_count

参考:https://stackoverflow.com/questions/16854280/a-variable-modified-inside-a-while-loop-is-not-remembered

 

1.6 Windows换行转Linux换行

问题描述:Windows换行是“\r\n”,而Linux换行是“\n”;Windows上的编写shell文件直接传到Linux系统上运行会报错“$'\r': command not found”(用vim打开文件会看到行尾是^M),此时需要将“\r”删除。

处理办法:

shell脚本文件已传到Linux上使用sed删除----sed -i -r 's/\r$//g' file_name

shell脚本文件还在Windows上使用Notepad++编缉器转换----菜单----编缉----文档格式转换----转换为Unix格式

sehll脚本由python3动态生成----打开文件时使用newline指定生成文件的换行符,如file_obj = open("test.sh","w+",encoding="utf-8",newline="\n")

参考:https://www.zhihu.com/question/19751023

另附pycharm指定行分格符的方法----与上边说的shell脚本换行无关,即便pycharm指定换行符为“LF”不通过newline指定动态生成的文件换行符依然是“\r\n”----分以下三类情况讨论

 修改单个文件换行符----pycharm打开文件并切换到该文件----右下角有当前页面的换行符,在其上点击切换为“LF - Unix and OS X (\n)”

修改文件夹下所有文件换行符----pycharm打开项目----在工程窗口使用光标选中要修改换行符的文件夹----菜单----File----Line Separators----“LF - Unix and OS X (\n)”

指定后续新建文件换行符(不影响已有文件)----菜单----File----Setting----Code Style----Line separator----设置为“Unix and OS X (\n)”

参考:https://www.jetbrains.com/help/pycharm/configuring-line-endings-and-line-separators.html

 

二、输出查找类

2.1 tail读取指定行后内容

问题描述:我们可以用tail配合-n指定读取文件最后多少行,但如果文件是不定长的而我想读取第1行以后的所有行,这个场景该怎么实现呢。

处理办法:其实-n除了直接接数字还,可以在数字前使用“+”号表示从第几行开始读取。(head的-n有类似的操作head -n -2即表示读取到倒数第二行)

 

2.2 grep查找进程并过滤查找命令本身

问题描述:我们经常使用ps -ef | grep something的语句去查找进程(以便进一步获取pid等),但此时grep本身也会被打印出来,如下图所示。我们希望grep语句本身也被过滤掉。

处理办法:使用grep -v grep将grep语句去掉

 

2.3 grep打印匹配行的前后几行

问题描述:我们使用grep查找时默认只打印匹配行,这种实现是合理的,但有时候匹配行与前后部份是强关联的我们也想获取。

处理办法:我们可以使用-A num指示打印匹配行的后几行,使用-B num指示打印匹配行的前几行。

 

2.4 sed去除块注释

问题描述:在读取tomcat等配置文件时,如果只是直接grep那查找出的内容可能其实是在块注释之中,该项配置其实并不生效。我们希望能先将配置文件中先将所有注释先去除掉。

处理办法:此时可以使用sed '/regex/d'删除单行注释,使用sed '/star_line_regex/,/end_line_regex/d'来删除掉块注释(d换成p就可用作查找块)。具体到tomcat如下

cat tomcat-users.xml |sed '/<!--.*-->/d' | sed '/<!--/,/-->/d'

参考:https://askubuntu.com/questions/525974/how-to-remove-comments-from-an-xml-file

 

2.5 将字符串作为命令执行

问题描述:在shell脚本中我们有时希望使用一个变量保存要执行的命令,再用一个变量保存命令执行后得到的结果。在如下形式中我们需要写两遍命令,这是不符合复用思想的。

# 变量command保存要执行的命令pwd;第一次写pwd
command="pwd"
# 变量result保存要执行的命令pwd的结果;再次写pwd
result=`pwd`

处理办法:我们可以使用eval命令,将command变量中保存的字符串作为命令执行,代码如下。

# 变量command保存要执行的命令pwd;第一次写pwd
command="pwd"
# 变量result保存要执行的命令pwd的结果;使用eval $command代替再次敲写命令pwd
result=`eval $command`

参考:https://stackoverflow.com/questions/2005192/how-to-execute-a-bash-command-stored-as-a-string-with-quotes-and-asterisk

 

2.6  想将字符串作为命令执行时命令中同时有单引号和元字符

# awk必须使用单引号,但同时其内部有元字符$
result=`cat /etc/passwd | awk -F: '$3==0{print $1}'| wc -l`
# 如果直接不管三七二十一直接写成
# command="cat /etc/passwd | awk -F: '$3==0{print $1}'| wc -l"
# result=`eval $command`
# 那此时双引号,一方面会使其内的单引号的“所见即所得”功能失效
# 另一方面会根据其特性双引号内元字符会被解析
# 所以此时$command值为cat /etc/passwd | awk -F: '==0{print }'| wc -l
# 这样eval肯定会报错

处理办法:此时需要使用反斜框对双引号内的元字符进行转义。

command="cat /etc/passwd | awk -F: '\$3==0{print \$1}'| wc -l"
result=`eval $command`

 

2.7 输出base64编码

有时候有些字符串有特殊字符,此时我们可能会想要一种简单的方法对这些特殊字符进行处理,base64显然就是一种很方便的处理方法。

# 使用方法一:直接对文件进行base64
base64 /etc/passwd
# 使用方法二:对字符串进行base64
echo "test str" | base64
# 避免自动换行。base64默认每76字节换行,如果我们原本的目录就是去掉特殊字符,自动换行会引入\n
# 我们可使用-w 0参数关闭自动换行
cat /etc/passwd | base64 -w 0

 

三、其他问题

3.1 获取nginx版本号

问题描述:我们知道nginx可以通过-v/-V来获取版本信息,但如果直接将查询赋给变量就会发现不能成功,如下图所示。(另外要获取which命令的输出可同样处理。)

处理办法:变量没有承接成功的原因是nginx将信息输出来了stderr而不是stdout,要承接我们需要将stderr重定向到stdout。

nginx_version=`nginx -v 2>&1`

参考:https://serverfault.com/questions/794873/cant-store-nginx-version-to-variable

 

3.2 获取tomcat版本号

问题描述:tomcat的版本号并不在响应的Server头中,只显示在默认的index.jsp和默认的错误页面中,此时可以通过curl获取其版本号(判断tomcat有没有设置隐藏版本号)。但如果默认index.jsp被删除且自定义了错误页面我们该如何通过shell获取到tomcat的版本号呢。

处理办法:此时我们还有三种办法可以获取到版本号。

第一种,解压$CATALINA_HOME/lib/catalina.jar,到org\apache\catalina\util\ServerInfo.properties文件中查看版本号。这理论上对服务没有影响,但动服务器文件的做法并不是很好。

第二种,使用java -cp $CATALINA_HOME/lib/catalina.jar org.apache.catalina.util.ServerInfo使用查看版本号。不过注意查找版本号的服务并不一定是运行tomcat的前户,其环境变量中并不一定有java。

第三种,运行$CATALINA_HOME/bin/version.sh获取版本信息。这个本质上还是执行第二种中的语句,一样需要有java命令才能获取结果。

参考:https://community.rsa.com/docs/DOC-81702

 

3.3 crontab中文乱码甚至使程序终止

问题描述:手动在控制台运行脚本时程序运行无误,但使用crontab运行时当处理到中文程序直接终止退出(我的场景是python3将中文写入txt文件)。

问题原因:此问题是crontab环境与控制台环境不一致所致,更本质讲是crontab环境没有中文相应编码所致。

处理办法:在执行python的shell脚本中,在执行python脚本前加入声明:export LANG="en_US.UTF-8"

https://blog.csdn.net/qq_33792843/article/details/77749661

https://blog.51cto.com/kaifly/2358278

 

3.4 yum任何命令都卡死、无输出、Ctrl+C无法中断问题排查

yum卡死一般都是因为先前某个yum或rpm占用了锁没释放,可借助strace命令查看yum执行到哪出的问题。

strace yum search python3

 yum卡死一般可以通过删除以下文件处理:

rm /var/lib/rpm/__db*
rm /var/lib/rpm/.rpm.lock
rm /var/lib/rpm/.dbenv.lock

 参考:https://serverfault.com/questions/392589/yum-clean-hangs-what-to-try-next

posted on 2019-01-03 12:02  诸子流  阅读(2078)  评论(0编辑  收藏  举报