supervise启动lighttpd或其他daemon进程问题(linux shell)
[| 2011/10/09 23:27]
今天有同事问到为什么supervise启动lighttpd的时候,lighttpd的pid文件是空的。我试了下,发现果然如此。
首先猜想是不是supervise动了手脚导致程序getpid得到空值,写了个printf getpid的小例子跑了下发现正常。
后来尝试用supervise启动lighttpd,发现supervise每隔1s就尝试启动lighttpd,即使lighttpd已经正常运行了。用刚才的小例子时不会重复尝试,只有被保护程序挂掉后才尝试重启。
后来突然想到lighttpd的两次fork。由于lighttpd进程是以daemon进程形式运行的,在启动过程中有两次fork子进程,然后父进程退出的操作。
supervise中,启动被监控程序的流程是supervise先fork一个自己,子进程调用execvp来启动被监控程序。父进程记录fork时获得的进程号,监控起来。显然,lighttpd第一次fork后,子进程就已经退出了,故supervise以为被监控进程挂了,于是尝试再次启动lighttpd。由于端口被占用的缘故,lighttpd未能启动,由于lighttpd的启动会清空pid文件,而启动失败又没有往里面写入有效进程号,所以pid文件就是空的了。
不使用supervise,通过普通方式两次启动lighttpd,第二次报端口被占用,此时pid文件为空,验证了以上的推论。
首先猜想是不是supervise动了手脚导致程序getpid得到空值,写了个printf getpid的小例子跑了下发现正常。
后来尝试用supervise启动lighttpd,发现supervise每隔1s就尝试启动lighttpd,即使lighttpd已经正常运行了。用刚才的小例子时不会重复尝试,只有被保护程序挂掉后才尝试重启。
后来突然想到lighttpd的两次fork。由于lighttpd进程是以daemon进程形式运行的,在启动过程中有两次fork子进程,然后父进程退出的操作。
supervise中,启动被监控程序的流程是supervise先fork一个自己,子进程调用execvp来启动被监控程序。父进程记录fork时获得的进程号,监控起来。显然,lighttpd第一次fork后,子进程就已经退出了,故supervise以为被监控进程挂了,于是尝试再次启动lighttpd。由于端口被占用的缘故,lighttpd未能启动,由于lighttpd的启动会清空pid文件,而启动失败又没有往里面写入有效进程号,所以pid文件就是空的了。
不使用supervise,通过普通方式两次启动lighttpd,第二次报端口被占用,此时pid文件为空,验证了以上的推论。
gdb查看结构体更美观
[| 2011/10/09 14:42]
直接p *abc的话会出来一大团东西,好处是最短的垂直空间内能显示完,坏处是层次结构不好找。
在gdb里运行一下set print pretty on
再输出就是层次结构了。
在gdb里运行一下set print pretty on
再输出就是层次结构了。
浏览器: F5 和 Ctrl+F5的区别(两种强制刷新的不同)
[| 2011/09/30 11:10]
以前只知道ctrl+f5是忽略缓存强制刷新所有内容,对f5的作用一直不太清晰,这篇文章讲的很清晰。
并且学到一点,原来ctrl+f5还可以强制网络上的proxy也更新内容
http://www.cnblogs.com/cxd4321/archive/2009/03/11/1408425.html
Browser: F5 vs Ctrl+F5
在浏览器里中,按F5键或者点击Toobar上的Refresh/Reload图标(简称F5),和做F5同时按住Ctrl键(简称Ctrl+F5),效果是明显不一样的,通常Ctrl+F5明显要让网页Refresh慢一些,到底两者有什么区别呢?
在上一篇技术文章中,说到了Expires、Last-Modified/If-Modified-Since和ETag/If-None-Match这些HTTP Headers,F5/Ctrl+F5和这些有莫大关系。
假如我第一次访问过http://www.example.com,这个网页是个动态网页,每次访问都会去访问Server,但是它包含一个一个静态资源http://www.example.com/logo.gif,浏览器在显示这个网页之前需要发HTTP请求获取这个logo.gif文件,返回的HTTP response包含这样的Headers:
Expires: Thu 27 Nov 2008 07:00:00 GMT
Last-Modified: Fri 30 Nov 2007 00:00:00 GMT
那么浏览器就会cache住这个logo.gif文件,直到2008年11月27日7点整,或者直到用户有意清空cache。
下次我再通过bookmark或者通过在URI输入栏直接敲字的方法访问http://www.example.com的时候,浏览器一看本地有个logo.gif,而且它还没过期呢,就不会发HTTP request给server,而是直接把本地cache中的logo.gif显示了。
F5的作用和直接在URI输入栏中输入然后回车是不一样的,F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的Response中有Expires Header。所以,当我在当前http://www.example.com网页中按F5的时候,浏览器会发送一个HTTP Request给Server,但是包含这样的Headers:
If-Modified-Since: Fri 30 Nov 2007 00:00:00 GMT
实际上Server没有修改这个logo.gif文件,所以返回一个304 (Not Modified),这样的Response很小,所以round-trip耗时不多,网页很快就刷新了。
上面的例子中没有考虑ETag,如同在上一篇技术文章中所说,最好就不要用ETag,但是如果Response中包含ETag,F5引发的Http Request中也是会包含If-None-Match的。
那么Ctrl+F5呢? Ctrl+F5要的是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样就逼着Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。
实际上,为了保证拿到的是从Server上最新的,Ctrl+F5不只是去掉了If-Modified-Since/If-None-Match,还需要添加一些HTTP Headers。按照HTTP/1.1协议,Cache不光只是存在Browser终端,从Browser到Server之间的中间节点(比如Proxy)也可能扮演Cache的作用,为了防止获得的只是这些中间节点的Cache,需要告诉他们,别用自己的Cache敷衍我,往Upstream的节点要一个最新的copy吧。
在IE6中,Ctrl+F5会添加一个Header
Pragma: no-cache
在Firefox 2.0中,Ctrl+F5会添加两个
Pragma: no-cache
Cache-Control: max-age=0
作用就是让中间的Cache对这个请求失效,这样返回的绝对是新鲜的资源
并且学到一点,原来ctrl+f5还可以强制网络上的proxy也更新内容
http://www.cnblogs.com/cxd4321/archive/2009/03/11/1408425.html
Browser: F5 vs Ctrl+F5
在浏览器里中,按F5键或者点击Toobar上的Refresh/Reload图标(简称F5),和做F5同时按住Ctrl键(简称Ctrl+F5),效果是明显不一样的,通常Ctrl+F5明显要让网页Refresh慢一些,到底两者有什么区别呢?
在上一篇技术文章中,说到了Expires、Last-Modified/If-Modified-Since和ETag/If-None-Match这些HTTP Headers,F5/Ctrl+F5和这些有莫大关系。
假如我第一次访问过http://www.example.com,这个网页是个动态网页,每次访问都会去访问Server,但是它包含一个一个静态资源http://www.example.com/logo.gif,浏览器在显示这个网页之前需要发HTTP请求获取这个logo.gif文件,返回的HTTP response包含这样的Headers:
Expires: Thu 27 Nov 2008 07:00:00 GMT
Last-Modified: Fri 30 Nov 2007 00:00:00 GMT
那么浏览器就会cache住这个logo.gif文件,直到2008年11月27日7点整,或者直到用户有意清空cache。
下次我再通过bookmark或者通过在URI输入栏直接敲字的方法访问http://www.example.com的时候,浏览器一看本地有个logo.gif,而且它还没过期呢,就不会发HTTP request给server,而是直接把本地cache中的logo.gif显示了。
F5的作用和直接在URI输入栏中输入然后回车是不一样的,F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的Response中有Expires Header。所以,当我在当前http://www.example.com网页中按F5的时候,浏览器会发送一个HTTP Request给Server,但是包含这样的Headers:
If-Modified-Since: Fri 30 Nov 2007 00:00:00 GMT
实际上Server没有修改这个logo.gif文件,所以返回一个304 (Not Modified),这样的Response很小,所以round-trip耗时不多,网页很快就刷新了。
上面的例子中没有考虑ETag,如同在上一篇技术文章中所说,最好就不要用ETag,但是如果Response中包含ETag,F5引发的Http Request中也是会包含If-None-Match的。
那么Ctrl+F5呢? Ctrl+F5要的是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样就逼着Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。
实际上,为了保证拿到的是从Server上最新的,Ctrl+F5不只是去掉了If-Modified-Since/If-None-Match,还需要添加一些HTTP Headers。按照HTTP/1.1协议,Cache不光只是存在Browser终端,从Browser到Server之间的中间节点(比如Proxy)也可能扮演Cache的作用,为了防止获得的只是这些中间节点的Cache,需要告诉他们,别用自己的Cache敷衍我,往Upstream的节点要一个最新的copy吧。
在IE6中,Ctrl+F5会添加一个Header
Pragma: no-cache
在Firefox 2.0中,Ctrl+F5会添加两个
Pragma: no-cache
Cache-Control: max-age=0
作用就是让中间的Cache对这个请求失效,这样返回的绝对是新鲜的资源
HTTP1.0下HTTP_HOST允许为空
[| 2011/09/21 22:04]
今天遇到lighttpd的一个奇异问题,幸亏高人指点,原来HTTP1.0下允许host为空,而1.1协议则要求host必须有值,否则返回400错误。
贴鸟哥帖子一篇:http://www.laruence.com/2008/08/28/483.html 写的很好,我就不重新轮一个帖子了。
昨天xuepeng师兄提出一个问题是 $_SERVER['HTTP_HOST']为空, 经过我翻看RFC文档以及测试,得出结论如下:
在http 1.1中, host字段是不能为空的,如果为空, 服务器会认为是bad request
但是在http 1.0中, host字段是可以为空的. 如:
<?php
$fp = fsockopen("localhost", 80, $errno, $errstr, 30);
$header = "GET /index.php";
$header .= " HTTP/1.0
";
$header .= "Connection:Close
";
fwrite($fp, $header);
echo fread($fp, 1024);
fclose($fp);
?>
其中,主机的index.php只是var_dump($_SERVER['HTTP_HOST']);
可以看到,当你指明使用http 1.0协议的时候, 请求正常,返回结果是false;
但是如果你指明协议是http 1.1 :
<?php
$fp = fsockopen("localhost", 80, $errno, $errstr, 30);
$header = "GET /index.php";
$header .= " HTTP/1.1
";
$header .= "Connection:Close
";
fwrite($fp, $header);
echo fread($fp, 1024);
fclose($fp);
?>
则结果是400 bad request;
究其原因是因为在HTTP1.0的时候, 并没有设想到现在有这么多服务器共用一个IP的情况(virtual host), 而在HTTP1.1的时候,加入了对多个HOST共用一个IP的支持.
以下文字摘自RFC2616:
14.23 Host
The Host request-header field specifies the Internet host and port
number of the resource being requested, as obtained from the original
URI given by the user or referring resource (generally an HTTP URL,
Fielding, et al. Standards Track [Page 128]
RFC 2616 HTTP/1.1 June 1999
as described in section 3.2.2). The Host field value MUST represent
the naming authority of the origin server or gateway given by the
original URL. This allows the origin server or gateway to
differentiate between internally-ambiguous URLs, such as the root “/”
URL of a server for multiple host names on a single IP address.
Host = “Host” “:” host [ ":" port ] ; Section 3.2.2
A “host” without any trailing port information implies the default
port for the service requested (e.g., “80″ for an HTTP URL). For
example, a request on the origin server for
would properly include:
GET /pub/WWW/ HTTP/1.1
Host: www.w3.org
A client MUST include a Host header field in all HTTP/1.1 request
messages . If the requested URI does not include an Internet host
name for the service being requested, then the Host header field MUST
be given with an empty value. An HTTP/1.1 proxy MUST ensure that any
request message it forwards does contain an appropriate Host header
field that identifies the service being requested by the proxy. All
Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
status code to any HTTP/1.1 request message which lacks a Host header
field.
以下省略…..
贴鸟哥帖子一篇:http://www.laruence.com/2008/08/28/483.html 写的很好,我就不重新轮一个帖子了。
昨天xuepeng师兄提出一个问题是 $_SERVER['HTTP_HOST']为空, 经过我翻看RFC文档以及测试,得出结论如下:
在http 1.1中, host字段是不能为空的,如果为空, 服务器会认为是bad request
但是在http 1.0中, host字段是可以为空的. 如:
<?php
$fp = fsockopen("localhost", 80, $errno, $errstr, 30);
$header = "GET /index.php";
$header .= " HTTP/1.0
";
$header .= "Connection:Close
";
fwrite($fp, $header);
echo fread($fp, 1024);
fclose($fp);
?>
其中,主机的index.php只是var_dump($_SERVER['HTTP_HOST']);
可以看到,当你指明使用http 1.0协议的时候, 请求正常,返回结果是false;
但是如果你指明协议是http 1.1 :
<?php
$fp = fsockopen("localhost", 80, $errno, $errstr, 30);
$header = "GET /index.php";
$header .= " HTTP/1.1
";
$header .= "Connection:Close
";
fwrite($fp, $header);
echo fread($fp, 1024);
fclose($fp);
?>
则结果是400 bad request;
究其原因是因为在HTTP1.0的时候, 并没有设想到现在有这么多服务器共用一个IP的情况(virtual host), 而在HTTP1.1的时候,加入了对多个HOST共用一个IP的支持.
以下文字摘自RFC2616:
14.23 Host
The Host request-header field specifies the Internet host and port
number of the resource being requested, as obtained from the original
URI given by the user or referring resource (generally an HTTP URL,
Fielding, et al. Standards Track [Page 128]
RFC 2616 HTTP/1.1 June 1999
as described in section 3.2.2). The Host field value MUST represent
the naming authority of the origin server or gateway given by the
original URL. This allows the origin server or gateway to
differentiate between internally-ambiguous URLs, such as the root “/”
URL of a server for multiple host names on a single IP address.
Host = “Host” “:” host [ ":" port ] ; Section 3.2.2
A “host” without any trailing port information implies the default
port for the service requested (e.g., “80″ for an HTTP URL). For
example, a request on the origin server for
would properly include:
GET /pub/WWW/ HTTP/1.1
Host: www.w3.org
A client MUST include a Host header field in all HTTP/1.1 request
messages . If the requested URI does not include an Internet host
name for the service being requested, then the Host header field MUST
be given with an empty value. An HTTP/1.1 proxy MUST ensure that any
request message it forwards does contain an appropriate Host header
field that identifies the service being requested by the proxy. All
Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
status code to any HTTP/1.1 request message which lacks a Host header
field.
以下省略…..
博客加上301到www域名跳转
[| 2011/09/19 20:33]
我比较喜欢上网站时省略前面的www,在做博客的时候整体设计上url也都是不带www的,后来统计发现用户和搜索引擎都是带www和不带www一起访问和收录的,导致非常乱,一直比较懒,没有加301跳转,今天忍无可忍,加上了。
非常简单,在nginx配置文件里加上:
if ($host = 'snooda.com' )
{
rewrite ^/(.*)$ http://www.snooda.com/$1 permanent;
}
在博客ci框架里设置:
$config['base_url'] = 'http://www.snooda.com/';
重启nginx后ok了。
不过需要注意,在一些统计脚本里我还写的是不带www的,这样会导致很多跳转,需要手动改过来。
非常简单,在nginx配置文件里加上:
if ($host = 'snooda.com' )
{
rewrite ^/(.*)$ http://www.snooda.com/$1 permanent;
}
在博客ci框架里设置:
$config['base_url'] = 'http://www.snooda.com/';
重启nginx后ok了。
不过需要注意,在一些统计脚本里我还写的是不带www的,这样会导致很多跳转,需要手动改过来。
CentOS5上安装encfs及boost
[| 2011/09/16 15:01]
最近要用到encfs,于是决定安装一下,encfs依赖于fuse,这个经过测试是可用的。yum search encfs,发现库里有,直接装上去了,前面一切顺利,在建立加密分区的最后一步,提示了一个:
terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
what(): boost::filesystem::path: invalid name ".encfs6.xml" in path: "/root/ef/.encfs6.xml"
看了一下版本,装的是1.4.2版的encfs和1.33.1版的boost。而encfs官网上要求的是1.34版boost,看来问题出在了这里。
于是上网搜了一下boost的rpm包(直接编译非常慢且很耗内存,我的小vps根本不行,只能装rpm),在:
http://rpms.plnet.rs/centos5-i386/RPMS.all/
搜到了boost1.34.1。wget回来用rpm -i安装时提示找不到libicui18n.so,yum了一下发现我装过了,看来是版本过旧。下了libicu-4.0.3装上后ok了。然后yum安装encfs,发现在yum里还是依赖boost,无语了,直接编译一个算了。比版本库里的还新。
于是去encfs官网下载最新的1.7.4,configure了一下,提示没有boost,想起来忘了装devel。把devel下载下来装上后提示差rlog,用yum装上rlog-devel后顺利编译安装。
建立加密分区的过程一切顺利,但挂载的时候提示:
fuse: failed to exec fusermount: Permission denied
原来需要将当前用户加到fuse组里。
ok,现在可以用了。
terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
what(): boost::filesystem::path: invalid name ".encfs6.xml" in path: "/root/ef/.encfs6.xml"
看了一下版本,装的是1.4.2版的encfs和1.33.1版的boost。而encfs官网上要求的是1.34版boost,看来问题出在了这里。
于是上网搜了一下boost的rpm包(直接编译非常慢且很耗内存,我的小vps根本不行,只能装rpm),在:
http://rpms.plnet.rs/centos5-i386/RPMS.all/
搜到了boost1.34.1。wget回来用rpm -i安装时提示找不到libicui18n.so,yum了一下发现我装过了,看来是版本过旧。下了libicu-4.0.3装上后ok了。然后yum安装encfs,发现在yum里还是依赖boost,无语了,直接编译一个算了。比版本库里的还新。
于是去encfs官网下载最新的1.7.4,configure了一下,提示没有boost,想起来忘了装devel。把devel下载下来装上后提示差rlog,用yum装上rlog-devel后顺利编译安装。
建立加密分区的过程一切顺利,但挂载的时候提示:
fuse: failed to exec fusermount: Permission denied
原来需要将当前用户加到fuse组里。
ok,现在可以用了。
gitweb安装及lighttpd配置
[| 2011/09/03 18:35]
由于前段时间已经把自己开发的代码都纳入到了git版本库的管理。维护代码顺畅了很多。不过查看diff还是有些麻烦,命令行使用起来很繁琐,win下的客户端又要把代码都check下来才能查看。于是决定在server上搭一个gitweb。
由于有yum,安装软件包简单了很多,直接yum install gitweb即可。
然后开始配置gitweb,修改/etc/gitweb.conf
设置our $projectroot为git库目录
设置$feature{'blame'}{'default'} = [1]; 这样就可以查看每个文件的修改历史了。很不错。
然后下一步需要给gitweb配置一个webserver。在我的server上可选的有nginx和lighttpd。由于最近在搞lighttpd,所以决定用lighttpd来作为gitweb的前段server。
首先在lighttpd中打开cgi模块的支持。
配置lighttpd.conf,给gitweb开个新端口,并配置相应的rewrite规则和验证规则
$SERVER["socket"] == "0.0.0.0:9999" {
auth.debug = 1
auth.backend = "htdigest"
auth.backend.htdigest.userfile = "lighttpd.htdigest"
auth.require = ( "" =>
(
"method" => "digest",
"realm" => "Password",
"require" => "valid-user"
)
)
server.document-root = "/var/www/git"
url.rewrite = ("^/static/(.*)$" => "/static/$1" ,
"^(.*)$" => "/gitweb.cgi$1"
)
}
上述配置规则表明,gitweb可从9999端口访问,lighttpd的mod_auth配置debug级别为1,类型为htdigest,指定密码文件,指定document_root和rewrite规则。
这里的htdigest就不多写了,网上资料很多,就是对密码和其他字段md5加密保存并验证的东西。
rewrite规则要注意,静态文件请求不进行rewrite,对于其他请求,统一rewrite到gitweb.cgi,如果配置错误,可能会在gitweb页面报404错误(找不到项目),让人摸不到头脑。验证方法是:如果web页面看到404找不到项目的错误,可以在server上手动执行gitweb.cgi,如果可以得到结果,可以判断是rewrite参数配置错误。
由于有yum,安装软件包简单了很多,直接yum install gitweb即可。
然后开始配置gitweb,修改/etc/gitweb.conf
设置our $projectroot为git库目录
设置$feature{'blame'}{'default'} = [1]; 这样就可以查看每个文件的修改历史了。很不错。
然后下一步需要给gitweb配置一个webserver。在我的server上可选的有nginx和lighttpd。由于最近在搞lighttpd,所以决定用lighttpd来作为gitweb的前段server。
首先在lighttpd中打开cgi模块的支持。
配置lighttpd.conf,给gitweb开个新端口,并配置相应的rewrite规则和验证规则
$SERVER["socket"] == "0.0.0.0:9999" {
auth.debug = 1
auth.backend = "htdigest"
auth.backend.htdigest.userfile = "lighttpd.htdigest"
auth.require = ( "" =>
(
"method" => "digest",
"realm" => "Password",
"require" => "valid-user"
)
)
server.document-root = "/var/www/git"
url.rewrite = ("^/static/(.*)$" => "/static/$1" ,
"^(.*)$" => "/gitweb.cgi$1"
)
}
上述配置规则表明,gitweb可从9999端口访问,lighttpd的mod_auth配置debug级别为1,类型为htdigest,指定密码文件,指定document_root和rewrite规则。
这里的htdigest就不多写了,网上资料很多,就是对密码和其他字段md5加密保存并验证的东西。
rewrite规则要注意,静态文件请求不进行rewrite,对于其他请求,统一rewrite到gitweb.cgi,如果配置错误,可能会在gitweb页面报404错误(找不到项目),让人摸不到头脑。验证方法是:如果web页面看到404找不到项目的错误,可以在server上手动执行gitweb.cgi,如果可以得到结果,可以判断是rewrite参数配置错误。
Linux命令行启动项管理工具ntsysv
[| 2011/09/03 00:04]
linux下要想管理启动项,直接修改/etc/rc.*是最直接的方法,但易用性很差,且易出错。使用一些工具就显得比较必要。
chkconfig是比较经典的一个工具,直观,用起来也方便,不过老是在命令行敲敲敲的,腻了。
于是用了一下在控制台下的图形管理工具:ntsysv。有了可视化界面,感觉爽了不少。上下键移动,空格设置选中/非选中状态,tab切换选区。
chkconfig是比较经典的一个工具,直观,用起来也方便,不过老是在命令行敲敲敲的,腻了。
于是用了一下在控制台下的图形管理工具:ntsysv。有了可视化界面,感觉爽了不少。上下键移动,空格设置选中/非选中状态,tab切换选区。
lighttpd中UNUSED宏的作用
[| 2011/08/23 11:02]
在lighttpd代码中,出现过很多UNUSED(srv)这种代码,查看代码发现#define UNUSED(x) ( (void)(x) ) 这个宏。
看起来没什么用。研究了一下,确实在逻辑上没有用,只是为了防止编译器报unused variable。
看起来没什么用。研究了一下,确实在逻辑上没有用,只是为了防止编译器报unused variable。
linux下screen关闭闪屏
[| 2011/08/19 23:24]
在linux下用screen时,当移动到行首或者行尾时,再尝试移动屏幕就会闪烁一下,非常郁闷,并且似乎只有secureCRT调成我常用的那个主题的时候才会闪,黑背景不闪,以为是bug。今天突然看见一篇文章说这是screen的一个功能。可以关闭。很happy
关闭screen屏幕闪动只需要使用CTRL-a CTRL-g,也就是先输入CTRL + a,再输入CTRL + g。
如果想永远关闭screen的闪屏功能,需要修改配置文件。在CentOS中可以修改/etc/screenrc,修改这个文件将对所有用户生效。对单个用户生效可只修改自己的配置文件。在$HOME/.screenrc中加入下面的话:
vbell off
其实这与vi中的visualbell功能很是类似。在vi中关闭闪屏,是使用:set novisualbell命令。
关闭screen屏幕闪动只需要使用CTRL-a CTRL-g,也就是先输入CTRL + a,再输入CTRL + g。
如果想永远关闭screen的闪屏功能,需要修改配置文件。在CentOS中可以修改/etc/screenrc,修改这个文件将对所有用户生效。对单个用户生效可只修改自己的配置文件。在$HOME/.screenrc中加入下面的话:
vbell off
其实这与vi中的visualbell功能很是类似。在vi中关闭闪屏,是使用:set novisualbell命令。