命令行下使用 sort 对中文内容排序,可能会失效,应该是字符集的问题,命令行前面加“LC_ALL=C”可解。
如:LC_ALL=C sort wuliu.txt | uniq > wuliu-result.txt
关于LC_ALL请参考:
https://blog.csdn.net/ict2014/article/details/23946471
命令行下使用 sort 对中文内容排序,可能会失效,应该是字符集的问题,命令行前面加“LC_ALL=C”可解。
如:LC_ALL=C sort wuliu.txt | uniq > wuliu-result.txt
关于LC_ALL请参考:
https://blog.csdn.net/ict2014/article/details/23946471
与xargs命令最初相识是在发现一个磁盘满了,具体是在/var/spool/clientmqueue,主要原因是系统中有用户开启了crontab,而crontab中执行的程序有输出内容,输出内容会以邮件形式发给cron的用户,而sendmail没有启动所以就产生了这些文件。关于更详细的原理,可以参考我之前的文章:crontab命令的使用介绍及我的体会。
仅仅解决出现多文件的方法比较简单,在命令后加上“> /dev/null 2>&1”即可,表示程序员输出和运行错误都放到黑洞里面去,这样就不会产生文件了。
如果是要解决删除多文件的问题,则进入这个文件夹,执行“ls | xargs rm -f ”即可。xargs可以从管道中循环读取文件,一次一次的把信息输送给后面的“rm -f”。
请注意以上措辞:“一次一次的”,那么这个一次一次,是指“一个一个”还是“一批一批”呢?
很杯具,当时不求甚解,未能深入学习xargs,误解为“一个一个”。
最近在写一个程序时,需要处理一个文件中的行数据。平时都是使用php的fopen再fgets解决问题,但这次懒得套用这一套了,于是想使用管道把数据传送给php脚本。
而php脚本也利用$argv这个数组来获取命令行输入的参数,那么很简单的,获取$argv[1],就可以了。如“php a.php b”,$argv[0]为文件名a.php,$argv[1]就是后面的参数b了。于是想当然的:cat uid.txt | xargs php a.php 。
最终发现,uid.txt中有近4千行的数据,但是只处理了4行。那么,既然出现问题就边解决边学习吧!
使用:cat uid.txt | xargs echo > file.out
发现 file.out文件果然就是四行,但是每行都很长。。。。。
如下,uid.txt内容为:(“......”表示很多行)
以下是引用片段: 1234567890 ...... 2234567890 ...... 3234567890 ...... 4234567890 ...... |
那么file.out的结果为:
以下是引用片段: 第一行:1234567890 ...... 第二行:2234567890 ...... 第三行:3234567890 ...... 第四行:4234567890 ...... |
所以,程序处理每一行的第一个了,剩下的全部被忽略。而我期望的结果是xargs每次给我一行。
那么寻求man的帮助吧:
以下是引用片段: --max-chars=max-chars, -s max-chars --max-args=max-args, -n max-args |
首先看-s参数,它提示说每次的输出不能超过131072 bytes,从结果上看上去它每次都往最大的值释放数据。再看-n参数,提示我们可以使用这个参数指定每次从源文件中取几行数据,那么OK,搞定了!如下:cat uid.txt | xargs -n 1 php a.php。问题解决。
更进一步的:
1:其实每个系统对于参数列表的大小都有限制。比如ARG_MAX一般至少定义为4096 bytes。如果超过了ARG_MAX,将产生shell错误:Argument list too lang,这个问题可以用上面说的xargs命令解决问题。
2:xargs的-s参数,根据实战的结果,貌似会在指定的值和真实数据中取得平衡,不会只依据-s指定的大小活生生的把源数据的一行撕裂成两行。
find命令很强大,但没有遇到大量文件时,没想到它是如此的高效,真有一种想干掉ls命令的感觉:
以下是引用片段: [root@thor104 f2r]# time ls -l /data2/friendresult/*/*/* [root@thor104 f2r]# time find /data2/friendresult/ -type f > friendfile.txt |
里面大约有16288个文件。
看来ls只能是作为一个日常的工具使用,只是find命令是基于什么样的原理才能怎么快呢?上网只找到一个不错的使用解说:《Linux Find 命令精通指南》。共享一下!
这是这个连锁反应:发现apache的log没有分日期、分正误记录 --> 改为分日期、分正误记录log --> 观察错误log,发现有大量404错误 --> 需要修正程序,发现文件路径错误 --> 本机使用Dreamweaver替换路径,提交SVN --> 部署到服务器上时发现文件太多、且分散在子目录中
怎么办?一个一个找一个一个上传?傻子才干!既然是在FreeBSD下,那就是用强大的命令行工具吧!实践中发现这个方法真的很实用,记录下来!
需求:把本目录下,包括子目录下的文件,把所有含有“/adm/images/c.gif”的地方替换为“/Admin/Images/c.gif”。
步骤:找出文件,找到地方,替换。
寻找命令:找到文件(find,ls),找到地方(grep),替换(sed)。
现在需要做的,就是组合起来。
查找资料,有前辈告诫:“find 命令是所有 Linux 命令中最有用的一个,同时也是最混乱的一个”,顿时奔溃。
还好,发现find命令有个叫“-exec”的,很是强大:find命令对匹配的文件执行该参数所给出的shell命令。相应命令的形式为'command' {} \;,注意{}和\;之间的空格。
个人理解:-exec参数中的“{}”是该参数前命令产生的结果的一个变量。感觉类似管道的作用了。
而且还可以有多个-exec参数,很是强大。基本上grep和sed都可以作为子命令在其中运行了。
如此一来,可以使用以下命令列出需要替换的字符串所在的行了:
以下是代码片段: find ./ -exec grep "/adm/images/c.gif" '{}' \; |
然后再使用一个-exec参数吧sed包含进来吧。
sed 的工作方式:
以下是引用片段: sed 实用工具按顺序逐行将文件读入到内存中。然后,它执行为该行指定的所有操作,并在完成请求的修改之后将该行放回到内存中,以将其转储至终端。完成了这一行上的所有操作之后,它读取文件的下一行,然后重复该过程直到它完成该文件。默认输出是将每一行的内容输出到屏幕上。在这里,开始涉及到两个重要的因素―首先,输出可以被重定向到另一文件中,以保存变化;第二,源文件(默认地)保持不被修改。sed 默认读取整个文件并对其中的每一行进行修改。不过,可以按需要将操作限制在指定的行上。 |
注意后面提到的源文件不会修改,不过sed提供了-i参数,可以做到控制是否可以修改源文件。-i参数的描述,Linux和FreeBSD下不太一样,后来也发现Linux在命令的使用方便上的确是要强于FreeBSD的。分述如下:
以下是引用片段: FreeBSD 4.7-STABLE下: Linux下: |
FreeBSD下说如果-i参数后面的后缀如果为0,则不产生备份文件,结果我试了好几次都没有搞定,不得已,使用了一个备份文件来存储源文件,然后修改源文件:
以下是代码片段: find ./ -exec grep "/adm/images/c.gif" '{}' \; -exec sed -i .bak 's/\/adm\/images\/c.gif/\/Admin\/Images\/c.gif/g' {} \; |
比如下面的就不行,老提示错误,望知情者指教:
以下是代码片段: find ./ -exec grep "/adm/images/c.gif" '{}' \; -exec sed -i 's/\/adm\/images\/c.gif/\/Admin\/Images\/c.gif/g' {} \; |
Linux下,可以不产生备份文件直接修改了:
以下是代码片段: find ./ -exec grep "/adm/images/c.gif" '{}' \; -exec sed -i 's/\/adm\/images\/c.gif/\/Admin\/Images\/c.gif/g' {} \; |
当然,需要强调的是:备份还是很重要的!切记切记!
本文环境如下:
以下是引用片段: FreeBSD: FreeBSD 4.7-STABLE Linux: |
另:
1:FreeBSD下如何查看sed的版本呢?
2:网上看见资料说,类似下面的语句应该是可以达到目的,当我在FreeBSD和Linux下都没有运行成功
以下是代码片段: sed -i 's/\/adm\/images\/c.gif/\/Admin\/Images\/c.gif/g' `grep -rf "/adm/images/c.gif"` |
参考资料:
以下是引用片段: Linux文件查找命令find,xargs详述 |
很久没有更新blog了,上来冒个泡。
之前,常用cut,sort,uniq命令的组合分析程序的log,或者查看数据以便统计。例如:cut -d "|" -f 4 | sort | uniq -n -r。
今天遇到一个问题,需要查看多个用户的操作记录。数据第一列可顺利的按照时间排序,然而用户名在中间,既然是log,那源数据便可能是多个用户的交叉记录了。比如:
以下是引用片段: time0 | userA | action time1 | userB | action time2 | userC | action time3 | userA | action time4 | userC | action time5 | userB | action time6 | userC | action time7 | userB | action |
很显然,我们希望的顺序是:
以下是引用片段: time0 | userA | action time3 | userA | action time1 | userB | action time5 | userB | action time7 | userB | action time2 | userC | action time4 | userC | action time6 | userC | action |
我们既想按照中间的数据的排序又要保持数据的完整性!也许可以用其他的命令实现这个,但我更倾向于使用常用的命令搞定复杂的事情。
其实sort命令是可以实现这个的。sort的-t选项可以实现cut的-d功能,再利用+m -n参数可以实现cut的-f的功能,只是,sort的这个+m -n是从0开始计数的。+m -n是指从第m个字段开始,到第n个字段排序,其中包含第m个但不包含第n个。比如:sort -t "|" +1 -2 filename 就可以得到我们想要的结果了。
sort的功能是排序,应用起来会有很多种排序的方式,可以用指定的参数来控制:
- d 按字典顺序排序,比较时仅字母、数字、空格和制表符有意义。这个选项对 uniq -d 后的结果尤为有用。
- f 将小写字母与大写字母同等对待。也就是忽略大小写。
- I 忽略非打印字符。
- M 作为月份比较:“JAN”<“FEB”
- r 按逆序输出排序结果。这个可与 -d 同时使用,实现数字从大到小的排列
还有一个很实用的功能,如果你想把一个过滤后的文件内容重新写入到原文件,那么- o 参数可以达到这个要求,但是效率呢?嗯,是个问题,看取舍了!毕竟这种情况重定向是不行的。
- o 输出文件 将排序输出写到输出文件中而不是标准输出,如果输出文件是输入文件之一,sort先将该文件的内容写入一个临时文件,然后再排序和写输出结果。
很多系统实用小工具就是用这种常用名字组建的,嗯哼。
精确的计算所需要的内存是很困难的,为了尽可能的精确,需要观察类似线上环境下观察服务器的负载和进程。毕竟如果不同的服务器配置和装的模块是有差异的,只有查看自己才可靠,所谓核心的东西要掌握在自己手里大概如此。。。。
一个简单可靠的法子是,在压力测试时,找到httpd进程,查看一个进程使用了多少的内存,然后看看总的进程,即可估算一下。
比如:
ps aux | grep httpd
查看每个httpd进程使用了多少内存,数字在第四列,格式为百分之几。
ps aux | grep httpd | wc -l
得到一共有多少进程,记得结果要减1,因为grep httpd也在结果中。
free
查看服务器内存总量,单位为K
然后就可以估算了。比如一个进程占2%的内存,有27个httpd,总内存为4148424。那就是:
php -r "echo 0.002*4148424*26/1024;"
结果为210.66215625M内存,这个只仅仅是为apache分配的。还得给其它服务留出足够空余的内存。而且考虑高峰期可能会比平时大12倍,这个时候仅仅考虑Apache就够了,嘿嘿。曾经出现过因磁盘IO过高导致服务器崩溃的场景。
如果怎么算都不能让服务器有空余的内存,就得考虑限制最大进程数了。使用MaxClient指令可以用来限制。
以上说得有误之处,还请各位指点!
1:<IfDefine [!]parameter-name> ... </IfDefine>
而parameter-name是在服务启动时,通过httpd命令行的 -Dparameter 这样的形式指定的。
2:<IfModule [!]module-file|module-identifier> ... </IfModule>
module可以是模块的标识符或者是编译模块时的文件名。比如,rewrite_module就是一个模块标识符,而mod_rewrite.c则是编译模块时的文件名。如果模块包含多个源代码文件,您应当使用包含 STANDARD20_MODULE_STUFF 字符串的那个。
而STANDARD20_MODULE_STUFF请参考:《编写第一个Apache模块――mod_helloworld》
3:User/Group指令用于设置实际提供服务的子进程的用户/组。为了使用这个指令,服务器必须以root身份启动和初始化。如果你以非root身份启动服务器,子进程将不能够切换至非特权用户/组,并继续以启动服务器的原始用户身份运行。如果确实以root用户启动了服务器,那么父进程将仍然以root身份运行。
Unix-userid是下列值之一:
以下是引用片段: 1:一个用户名/组:通过用户名/组引用用户/组 |
用于运行子进程的用户必须是一个没有特权的用户/组,这样才能保证子进程无权访问那些不想为外界所知的文件,同样的,该用户/组亦需没有执行那些不应当被外界执行的程序的权限。
进程的用户及层次关系可见:
以下是引用片段: [root@login yayu]# pstree -apu | grep http |-httpd,10914 -DSSL | |-httpd,8483,web -DSSL | |-httpd,8489,web -DSSL | |-httpd,8551,web -DSSL | |-httpd,8552,web -DSSL | |-httpd,8553,web -DSSL | |-httpd,8554,web -DSSL | |-grep,8558 http |
4:如果在<VirtualHost>外设置了一个ServerName,而一个请求不能与某个ServerName指令相匹配,它将会由第一个<VirtualHost>段所伺服。
5:ServerRoot指令设置了服务器所在的目录。一般来说它将包含conf/和logs/子目录。其它配置文件的相对路径即基于此目录 (比如Include或LoadModule)。而指定ServerRoot、DocumentRoot时不应包括最后的"/"。
6:Order指令控制默认的访问状态与Allow和Deny指令生效的顺序,变态的命令。
下面例子中,apache.org域中所有主机,除了foo.apache.org子域包含的主机被拒绝以外,其他都允许访问。而所有不在apache.org域中的主机都不允许访问,因为默认状态是拒绝对服务器的访问。
以下是引用片段: Order Allow,Deny Allow from apache.org Deny from foo.apache.org |
另一方面,如果上个例子中的Order指令改变为"Deny,Allow",将允许所有主机的访问。这是因为,不管配置文件中指令的实际顺序如何,"Allow from apache.org"指令会最后被评估到并覆盖之前的"Deny from foo.apache.org"。所有不在apache.org域中的主机也允许访问是因为默认状态被改变到了允许。说白了就是控制Allow和Deny两个指定的顺序。
不仔细看httpd.conf配置文件还不知道有这回事,汗。
ServerType这个配置选项指定如何运行Apache。Apache可以使用两种方法来运行:standalone(独立式)和inetd(超级守护进程式)。
standalone模式表示Apache进程以一个单独的守护进程方式在后台监听是否有客户端的请求,如果有则生成一个子进程来为其服务。在standalone模式下,apache进程一次性启动,运行期间一直驻留在内存中,尽管损耗了一定的系统资源,但接入信号反应快;而且子httpd进程在http请求完毕后并没有直接断掉,这样就可以重新用来接受新的http请求,请参考apache的keepalive指令(请看这里)。由于不存在对每个请求都启动新的apache根进程,所以它的效率更高。
inetd模式表示Apache服务不是以一个单独的守候进程的形式支持。而是由Inetd这个超级守候进程进行代劳,当它监听一个客户端的http请求的时候,再启动一个httpd进程为其服务。一个由inted运行的服务器进程在它结束对请求服务的同时立刻退出,虽然不占用了系统资源,但是也由此不适合应用在同时连接数量较多的系统。因为如果请求完毕后就结束httpd进程,会使服务器负担加重。
具体使用如下:
standalone模式
此种模式下,Apache服务器监听特定端口的连接请求。当用户发起特定端口地址的连接请求时,主服务器进程启动子httpd进程来响应该请求。
这样还需要告诉主服务器进程侦听的特定端口地址,使用命令:
以下是代码片段: Port [number] (缺省值为80) |
inetd模式
inetd是监听所有小于1024的端口连接请求的Internet守护进程(一个服务器进程)。与standalone模式不同,当客户系统发出到Apache服务器的连接请求时,inetd启动一个httpd进程,由此进程服务此请求,完成服务后即退出。
如果选择通过inetd服务器来运行Apache,需要编辑/etc/inetd.conf文件为Apache添加一条新的记录:
以下是代码片段: httpd stream tcp nowait httpd /etc/httpd/bin/httpd |
前段时间在看清华大学出版社出版的《Linux教程》(05年6月第一版)。在248页第十三章《进程》有一节是简述Linux进程的层次关系的,把操作系统自启动后都做了什么,说得比较清晰,看过后受益匪浅。
就是喜欢看这种能把整个框架说得比较清楚的文章!特抄来以共享:
当打开Linux系统,LILO(LInux LOader)找到Linux内核把它加载到内存。它初始化各种硬件,包括磁盘控制器。然后转到保护模式,加载操作系统,执行初始化各种内核数据结构的代码,例如inode和文件表。此进程的PID为0。它启动初试进程(init进程,PID为1)完成引导过程的其余工作。init进程启动守护进程kflushd、kupdate、kpiod和kswapd,其PID分别为2、3、4、5。Init进程然后初始化文件系统,安装根文件系统。接下来试着执行/sbin/init程序,在每一个激活的终端上执行minegetty进程(经常被称为getty进程)。getty进程设置终端属性,如波特率,这些属性在/etc/termcap文件中都有定义。它显示login:提示符,等待用户登录。
在login:提示符下,输入登录名并按回车键,getty进程产生一个子进程。它转变为以登录名为参数的登录进程。登录进程提示输入密码,并检查输入名和密码的有效性。如果两者均正确,登录进程产生一个子进程,它将转变为登录shell。如果登录进程没有在/etc/passwd文件中找到登录名或者输入的密码与/etc/passwd文件中(或者/etc/shadow文件)存放的密码不匹配,他将显示错误提示信息然后终止。控制权又回到getty进程,重新显示login:提示符。一旦进入登录shell,就可以完成自己的工作,还可以按<ctrl-D>键终止当前shell。如果这样做了,shell进程会终止,控制权又回到getty进程,再次显示login:提示符,又开始循环。
就是说,当登录到Linux系统,系统产生第一个进程,称为登录进程,它又创建登录shell。登录shell为所输入的命令创建进程,用以解释/执行命令。
两个Linux进程贯穿系统生命周期:swapper和init进程。监视终端行的getty进程,只要终端与系统关联上就会一直存在。登录进程和登录shell进程只有在登录时才存在。所有其它进程生存期较短,只在命令或者程序执行时短暂存在。
ps -ef 命令或者pstree命令可以用图的形式显示当前系统中执行进程的进程树,勾勒出进程间的父子关系。pstree命令显示的图比ps -ef命令更简洁。pstree显示的结果,前有“+”的是当前的后台进程,而前面的有“-”的是后续后台进程。pstree命令使用-h参数,输出用粗体(加亮)显示当前进程。使用“-a”选项,pstree显示带参数的命令。如“pstree 402 -a”可以显示PID为402的进程的那个的层次关系。
Bash shell可以使用ulimit显示用户可以同时执行的最大进程个数。TC shell下为limit。两个命令都可以用来显示硬件和操作系统资源的使用限制。
访问量上升,数据库压力大,怎么办?好办法是在中间挡一层缓存!这个缓存要求高效,不能比数据库慢,否则服务质量受影响;如果能把数据用hash打散存储到硬盘,也是可以的,不过在内存越来越便宜的今天,还是使用内存吧!
mysql也有自己的缓存,也是存储在内存的,但是有一个说法是:
以下是引用片段: 只能有一个实例 只要有写操作,mysql的query cache就失效 |
再说,如果mysql都抗不住了,怎么还能指望它提供的缓存呢?
所以我可以使用memcached了!他的好处和如何用可以参考:
以下是引用片段: |
开发时面对需求是个麻烦事,更漫长而闹心的是维护,所以我更关心的是memcached运行中的情况。还好的是,memcached的作者给我们提供查看运行情况的命令。主要是“stats”,使用方法为 “telnet ip 端口号”,登录后使用“stats”命令。
然后你可以看见很多内容,具体可以参考:《memcacche stats》
以下是引用片段: pid = process id |
着重说一下几个对观测很有用的项。
limit_maxbytes、bytes
memcached在存储的时候是可以设置失效时间的,但如果存储已经满了,那旧数据即使没有到过期时间,也会被移除。所以需要观察memcached存储是否已经满了,同时这对扩容也是有意义的参考。limit_maxbytes即总的存储大小,而bytes就是已经使用的大小,从这两个数据就可以看出在memcached启动时,我们为它分配的内存是否足够使用。
cmd_get、cmd_set
memcached启动后,我们对它一共做了多少次读取操作呢?从这两个参数可以观察出来。
get_hits、get_misses
使用memcached后,我们需要评估我们使用的策略是否合理。不能够使用中间缓存后,后端的数据库还是有较大的访问量,这样的话中间缓存就变得没有意义了。get_hits表示命中了多少次读取,即来memcached取到了多少有效数据;get_misses表示没有命中的次数,即此次来取数据的时候,memcached并没有你所查询的数据。如果没有清零统计数据的话,cmd_get = get_hits + get_misses。
memcached 的状态查询还有其它的命令,可以参考:《Memcached的stats命令》
如下:
stats reset
清空统计数据
stats malloc
显示内存分配数据
stats maps
这个不太确定,看源代码是把/proc/self/maps的数据显示出来。
stats cachedump slab_id limit_num
显示某个slab中的前limit_num个key列表,显示格式如下
ITEM key_name [ value_length b; expire_time|access_time s]
其中,memcached 1.2.2及以前版本显示的是 访问时间(timestamp)
1.2.4以上版本,包括1.2.4显示 过期时间(timestamp)
如果是永不过期的key,expire_time会显示为服务器启动的时间
stats cachedump 7 2
ITEM copy_test1 [250 b; 1207795754 s]
ITEM copy_test [248 b; 1207793649 s]
stats slabs
显示各个slab的信息,包括chunk的大小、数目、使用情况等
stats items
显示各个slab中item的数目和最老item的年龄(最后一次访问距离现在的秒数)
stats detail [on|off|dump]
设置或者显示详细操作记录
参数为on,打开详细操作记录
参数为off,关闭详细操作记录
参数为dump,显示详细操作记录(每一个键值get、set、hit、del的次数)
stats detail dump
PREFIX copy_test2 get 1 hit 1 set 0 del 0
PREFIX copy_test1 get 1 hit 1 set 0 del 0
PREFIX cpy get 1 hit 0 set 0 del 0