成功的路上总是困难重重、千辛万苦

王志勇 发表于 2019年09月11日 09:23

我从3年多以前开始用VPS之后,从那时开始学习、使用Shell命令、Shell编程。Shell命令具有最高权限,但是其功能远远不如PHP等编程语言。比如需要用命令自动修改某个文件,PHP等大多数编程语言只需打开文本文件、替换、写入这3个步骤。Shell编程要实现这3个步骤,会遇到各种困难,至今3年多,这个问题仍然没有完美解决,其困难如下:

困难1. 本来最好的方法是用cat命令加反引号,可以读取整个文件,例如a1=`cat /etc/ssh/sshd_config`; 然后替换$a1变量的数据,再写入$a1变量,这个过程就和PHP完全一样。但是问题出现了,反引号里的数值,会自动把所有的回车符,变成空格。写入的时候,所有的回车符变成了空格。因此,这个方案行不通。

困难2. 改用while read line的方法,逐行读取,但是在while read line这个循环语句里,循环里的赋值不允许循环外调用,例如这样:

a1=333;
cat /etc/ssh/sshd_config | while read line;
do a1=555;
done;
echo $a1;

运行的结果是333。

为了证明循环里的赋值不允许循环外调用,在上述的程序 do a1=555; 这一行之后再加入一行 echo $a1; 让其显示此时$a1的值,果不其然,结果是:
555
555
……
555
555
555
333

而一般的循环语句里,则循环里的赋值,允许循环外调用,例如这样:

a1='1111'; for ((a=1;a<=5;a++)); do a1='2222'; done; echo $a1;

运行的结果是2222。

Shell程序,为什么要在while read和for语句里这样设置一个区别呢

答案就是很可能困难1、困难2,都是因为Shell程序自身的bug。

Shell命令、Shell程序一个缺点是如果是作为公共项目,必须尽量用兼容性很强的语句。不能在这个系统下执行,另一个系统下不执行。例如我在项目里,最近遇到的一个不兼容的基本例子:

将所有字符转换成小写:

str=${str,,};

上述这个语句就可以把将所有字符转换成小写,在Ubuntu、Debian所有系统下自带的Bash正常运行;但是在CentOS系统下自带的Bash,就不运行。因此,这个语句就只能放弃,只能用这种方法,将所有字符转换成小写:

a1=$(echo 'CCC' | tr '[A-Z]' '[a-z]'); echo $a1;

Shell程序替换一个文件里的字符,3年多以前我花了很多时间测试方法,最后用的是这个方法,把文件中的所有fff替换成kkk,并写入文件:

sed -i "s/fff/kkk/g" /etc/data22.txt

用sed命令能实现。但是缺点是,如果需要替换多次,则需要写入多次文件,会导致硬盘频繁写入,影响计算机性能,或者增加数据写入出错的风险。(PHP等任何编程语言,则只需写入一次。)
如今又需要解决3年前的问题,现在依然只能用sed命令。

2条评论:
1   大致 2019-09-11 10:16
在shell里,while被认为是一个subshell。所以根本不是一个名空间。
所以在done的时候得用echo之类的传到外面去才行。例子很多,自己搜吧。

自由勇 2019-09-11 10:51
谢谢!如果用反引号或$()把while的结果传到外面,反引号或$()还是会把任何结果的回车符转成空格。
我用for循环试一下。

发表评论:
名字: (*必填)
博客: (可省)

正文:

  记住信息?

王志勇:1980-09-26 (44周岁)
程序设计,前端设计。

版权声明:本博客所有文章,均符合原创的定义,禁止转载,违者将必究;正确的方法是贴原文的标题和网址即可。

与此相关的链接
自由勇专栏

Blog存档 Archives

2022年07月
2022年06月(15)
2022年05月(20)
2022年04月(16)
2022年03月(9)
2022年02月(9)
2022年01月(10)
2021年 +

2020年 +
2019年 +
2018年 +
2016年-2017年(9)
2014年06月-09月(10)
2013年 +
2012年 +
2011年 +
2010年 +
2009年 +
2008年 +
2007年 +
2006年 +
2005年09月(4)

Copyright © 2006-2024 auiou.com All rights reserved.
此Blog程序由王志勇编写