■ 关于查看系统的一些版本信息
查看系统的发行版本可以用
cat /etc/issue 或者 cat /etc/redhat-release (Centos上)
查看系统的内核版本以及系统位数
uname -a
#或者
cat /proc/version
■ rpm -qa查看所有通过rpm安装的包
■ export [...] 如果有变量,则是把这个自定义变量转换成环境变量 其反义为declare。如果没有参数那就是显示出当前所有环境变量
■ 查找文件的方法
查找文件or命令可能会用到以下几种命令:locate,whereis,which,find等等
which 在$PATH中查找可执行文件,主要用于定位某个命令其文件到底在哪里
whereis和locate 这两个命令都是通过数据库来查找文件,因此比find要快很多。locate还可以用-r [正则]来模糊匹配。虽然还不清楚whereis的数据库是哪个,但是locate的数据库默认是/var/lib/mlocate/mlocate.db。这个数据库有默认的更新策略,手动更新可以用updatedb。
find find会实时地查找硬盘,find后面加上很多参数可以限定查找范围。比如
find [PATH] [OPTION] [ACTION] 其中OPTION可以有-mtime,-user <user>,-name <文件名>,-perm <mode>,-size <size>,-ctime等等。mtime和ctime这种的参数是一个
■ Linux文件的三个时间
mtime, atime和ctime的全称分别是modification time,access time,change time。中文名依次是修改时间,访问时间和状态时间。第一个和第三个容易混淆。每个的含义是:
>修改时间:文件的内容被最后一次修改的时间,我们经常用的ls -l命令显示出来的文件时间就是这个时间,当用vim对文件进行编辑之后保存,它的mtime就会相应的改变; >访问时间:对文件进行一次读操作,它的访问时间就会改变。例如像:cat、more等操作,但是像之前的state还有ls命令对atime是不会有影响的; >状态时间:当文件的状态被改变的时候,状态时间就会随之改变,例如当使用chmod、chown等改变文件属性的操作是会改变文件的ctime的。
■ xargs
把xargs写在管道的右边可以把左边传来的信息作为stdin来处理写在rm -f右边的命令。比如删除一批tar.gz文件的话可以:
ls | grep tar.gz$ | xargs rm -f
■ tar命令压缩与解压缩
tar -xvzf ...tar.gz 用于解压tar.gz的文件,可以加上-C <path> 来指定将tar包解压到相应的目录
tar -cvzf <tarfile> <file or path> 将文件或目录压缩为一个.tar.gz包
以上两个命令是带压缩的,如果只是单纯的打包解包的话去掉-z参数就好了
■ source
通过一种更NB的方式来执行linux命令和脚本(详细的跟父进程,子进程以及子进程的创建阻塞父进程等等有关),通常用来使配置文件生效比如source /etc/profile;source ~/.bash_profile
■ cut
切取。参数有
-d <sep>表示以sep为分隔符切取字串;
-f <field> field是个数字,表示切取-d指出后的第几个分段;
如 echo "a,b,c,d,e" | cut -d ',' -f 2 返回的就是b
■ /proc是个伪目录,它不占磁盘空间而是直接存在内存里面,由核心直接产生。它里面的文件记录了一些系统的信息,比如:
cpuinfo cpu信息
devices 核心配置的设备驱动列表
filesystems 文件系统信息
meminfo 各个存储器的信息
modules 核心模块的信息
net 网络协议状态
stat 系统状态
uptime 系统启动时间长度
version 核心版本
■ shell中的$
$0 表示shell的文件名,通常是/bin/bash
$1 表示脚本自身的名字
$2,3... 表示运行脚本时带的参数
$? 表示上一个命令的返回值,0是正常,其他值是异常
$* 表示所有参数的集合
■ free -m用于查看系统的内存情况,包括物理内存和swap,以m为单位。
■ nohup <cmd> & 将命令开启的进程放到后台运行,并且把stdout和stderr的输出全部导入到工作目录下的nohup.out文件中。一般用于开启服务器,监听进程等操作
■ 用户的自定义命令alias可以写在~/.bashrc中,这是针对一个用户的,针对所有用户的写在/etc/profile之类的地方。
格式: alias (自定义命令) = '...'
比如: alias rm='rm -f' 这样的话以后删除就不用再确认了
改完所有之后再source 一下这个文件使之生效。
*如果是说那种自己写一个脚本来定义一个命令的自定义命令的话,把脚本写好之后去掉后缀放到/usr/bin或者/usr/sbin这种PATH中包含的目录就好了
■ ping & telnet
ping后面加-c <count> 可以设置ping包的次数。ping用于测试网络的联通情况
telnet <ip> <port> 用于测试端口是否开放,只要显示出escape character is '^['字样就算是测试成功了
■ PATH读取的优先级
正如我们所知道的,一个命令的执行的第一步就是系统到相关的PATH目录下去读取命令的脚本。PATH的具体内容可以通过echo $PATH来查看が,那么在读取的时候读取各个PATH的优先级是什么样的呢?
比如我的手机上的PATH就是这样的:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/bin/X11:/usr/games,所以最开始从/usr/local/sbin中去读取。
当多个PATH目录中有重名的命令时肯定就用优先级高的命令啦,比如同样是python,/usr/local/bin在/usr/bin之前,所以运行python其实是运行了/usr/local/bin/python
■ 关于物理内存,虚拟内存,swap和调页
这其实是计算机知识吧。。非常没有把握,看官请不要被我误导。。
物理内存就是指实际内存(RAM),在硬件上就是用途不同于普通磁盘的一块储存空间。
虚拟内存在狭义上指windows的虚拟内存,即调用了一部分磁盘空间作为内存使用来缓解某些时候内存不足的情况。而在linux上虚拟内存基本等同于swap区。用户在安装linux 的时候可以手动设置swap的大小。
swap就如上面所说是linux的虚拟内存的代名词,其大小通常是物理内存的2-4倍
调页:当物理内存不够用,要启用swap等虚拟内存时,需要做的操作,或者说实现的过程就叫调页。具体来说,系统copy一些内存中页面(page,这个概念基本上就是指内存中为了方便使用事先划分好的一些区块)到swap中,这样就可以腾出一部分内存的空间供后面的计算使用。相对的,若要从swap中把数据弄回内存,操作也是差不多的。
调页从内存管理的角度而言还包含了调页算法和交换技术这两个概念。调页算法是指实现将最近不常用的页面还给磁盘,常用的留下来继续充当内存这样操作的算法,这种做法提高了内存和磁盘间调度的灵活性
交换技术则是指不是从页面的角度,而是把所属于一个进程的所有页面整个地搬进搬出内存,这样可以减少混乱和错误
■ env命令和source后面不加参数一样,都是列出当前所有环境变量
■ /var/log/secure中存放了登录系统,密码修改等操作的日志。可以从中查询到用户的登录情况
■ nslookup之后再命令行输入status可以查看当前DNS服务器的信息
■ 关于service命令
service可以管理linux上的各种服务。其本身是/sbin/service,它的运作原理是调用一些位于/etc/init.d下的各种服务的启停脚本。这些脚本里面都写了start,stop,status之类的函数供用户使用。所以在命令行中我们可以输入类似于:service httpd start ; service mysqld status这样的命令了。
■ last命令
last用于查看过去登录成功的用户记录。。要看登录失败的话得看/var/log/secure日志
■ sh -c "..."是另一个可以连续执行一连串命令的方法。
■ shell和bash的联系与区别
shell是一种统称,或者说是一类程序,它提供了一个可交互接口以连接操作系统和用户。shell不一定是字符界面,也有可能是图形界面。而/bin/bash 是linux shell中最常见和常用的一种。
■ vim和cat在显示机理上的不同
这两个命令都是常用的查看文件内容的指令,然而vim可以对文件进行编辑。不过在加载文件内容时,vim会把文件内容全部加载进内存再显示,当文件的内容非常大的时候,vim响应的速度就很慢了。另一方面,像cat,less,more这些命令的话都是一屏一屏地把内容加载进内存,所以不存在速度上的问题。
■ w
w可以查看系统总体信息,比如top的头几行信息以及who返回的那些用户登录情况
■ alias和unalias
alias的本意是“别名”。可以在shell给出的一些命令上再包装一层。格式:
alias alias_name="original_name -someparameters" 执行过这一条之后就可以用alias_name来执行命令
不带参数地只键入alias可以查看到当前所有alias。如果想要让某个alias开机自启动生效可以写进$HOME/.bashrc或者/etc/bashrc之类的地方。
unalias alias_name用于撤销一个alias,立即生效
■ dd
dd的作用是用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。
以下说明引用自http://blog.csdn.net/xizaihui/article/details/53307578
注意:指定数字的地*以下列字符结尾,则乘以相应的数字:b=512;c=1;k=1024;w=2 参数注释: if=文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >
of=文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >
ibs=bytes:一次读入bytes个字节,即指定一个块大小为bytes个字节。
obs=bytes:一次输出bytes个字节,即指定一个块大小为bytes个字节。
bs=bytes:同时设置读入/输出的块大小为bytes个字节。
cbs=bytes:一次转换bytes个字节,即指定转换缓冲区大小。
skip=blocks:从输入文件开头跳过blocks个块后再开始复制。
seek=blocks:从输出文件开头跳过blocks个块后再开始复制。
注意:通常只用当输出文件是磁盘或磁带时才有效,即备份到磁盘或磁带时才有效。
count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。
conv=conversion:用指定的参数转换文件。
ascii:转换ebcdic为ascii
ebcdic:转换ascii为ebcdic
ibm:转换ascii为alternate ebcdic
block:把每一行转换为长度为cbs,不足部分用空格填充
unblock:使每一行的长度都为cbs,不足部分用空格填充
lcase:把大写字符转换为小写字符
ucase:把小写字符转换为大写字符
swab:交换输入的每对字节
noerror:出错时不停止
notrunc:不截短输出文件
sync:将每个输入块填充到ibs个字节,不足部分用空(NUL)字符补齐。
dd这命令比我想象的要高级。。我用dd,只是用它创建一个指定大小的文件而已(利用/dev/zero)比如:
dd -if=/dev/zero -of=<目标文件> count=1 bs=10240 这样就可以创建一个10kb的文件了
■ /etc/profile & /etc/bashrc & $HOME/.bashrc & $HOME/.bash_profile
这四个文件进程涉及环境变量,bash的设置等等,其具体区别在网上搜了一下:
/etc/profile:此文件为系统的每个用户共用的环境信息,当用户第一次登录时,该文件被执行,并从/etc/profile.d目录的配置文件中搜集shell的设置,
/etc/bashrc:为每一个运行bash shell的用户执行此文件,当bash shell被打开时,该文件被读取。
~/.bash_profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,然后执行用户的.bashrc文件。
~/.bashrc:该文件包含专用于你的bash shell的信息。和.bash_profile不同的是用户登录时以及每次打开新的shell时,该文件都会被读取。事实上,这个文件的内容是先进行一些个性化设置后再读取/etc/bashrc
■ 文件的特殊权限 SUID,SGID,SBIT
SUID权限(体现在owner的x位上显示s)。SUID只对二进制程序有效,且仅在执行过程中有效。执行者将因为拥有SUID权限而在执行期间有程序拥有者的权限
比如普通用户可以passwd来修改/etc/shadow,相当于说普通用户对其有写权限。但是cat /etc/shadow是做不到的,因为/usr/bin/passwd执行文件的权限是-rwsr-xr-x。这说明,当普通用户运行此文件时会变身成root,因此修改了shadow文件。而/bin/cat的权限中并无s,运行它时普通用户仍然是普通用户
SGID权限(体现在group权限的x位显示s)。SGID也只对二进制程序有效,也可对文件或目录设置。与SUID类似,执行者在执行过程中会变身成为程序所有组的一员来执行程序。对于目录而言,相当于这个用户可以进入。
SBIT权限针对目录而言,体现在目录权限符末尾多出一位"t"。简单来说,有t位权限的目录表示除了root用户以外,其他具有该目录写权限的用户只有在该目录下创建新文件/目录的权限,而没有删除除了自己创建的文件/目录外的内容的权限。
■ file <某文件> 查看文件类型,比如是ASCII text,Data等各种类型
■ 防火墙iptables配置在/etc/sysconfig/iptables下。开机开启防火墙在/etc/init.d/iptables,也可以service iptables start/stop等等
■ SELinux可以通过set/getenforce 设置/获取selinux运行状态。在setenforce的时候可选参数为 Enforcing/Permissive/Disabled 分别代表开启/警告/关闭的状态。另外编辑/etc/selinux/config文件可以一劳永逸地关闭selinux
■ 关于守护进程的简要理解。守护进程向本地及网络的用户提供了linux系统功能的接口。即服务
守护进程还可分为独立守护进程和超级守护进程。超级守护进程是指用xinet这一个守护进程进行相关监听等工作,当请求进来的时候由xinet调用相关进程处理请求。
■ 之前知道mkdir -p <path>可以一次性递归地创建多级目录。除了一般的写法之外,还有mkdir -p {a,b}/{1,2}这样的写法。这样写的意思是在做了一个笛卡尔积,在当前目录下创建两个子目录a和b,然后再分别在a和b下各创建两个子目录1和2
■ chmod和chown都是可以用-R来表示递归的。同时chown还有chown -R <user:group> <file>这种一次性改变一整个目录的所属用户和用户组的方便写法
■ wc用于计数,可以接在管道右边也可以在后面直接接上文件,不同的参数表示统计不同的数量。
-l 表示统计行数 -w 表示统计单词个数 -m 表示统计字符个数 不加任何参数表示统计 '行数\t词数\t字符数\n'
■ sort可以接在管道右边,用于排序。
-f 忽略大小写
-b 忽略开头所有空白字符
-M 以月份名(JAN,FEB...)排序
-n 以数字大小排序
-u 同uniq,相同的数据只列出一次
-k xx 以某个field排序
■ md5sum <file>可以方便地统计一个文件的md5值。需要注意的是同样的文件在linux中和在windows中的md5等hash值并不一定相同。这是因为两者文件系统不一样,在传输过后有可能会有用\0填补空白部分的这种做法。
■ killall xxx相当于ps -ef | grep xxx后用kill -9所有这些进程,比较危险,谨慎操作
■ source和sh <file>以及./<file>来执行文件的不同点
传统的sh 或者 ./xx 这种形式采用创建一个新的bash子进程,然后把脚本放到这个新bash中去执行。子进程开启后父进程挂起且子进程中定义的变量以及操作返回的数据等等都不传回父进程,传回父进程的只有子进程执行的返回码。而source这种方式,在子进程开启后父进程继续运行,没有挂起。此外子进程中定义的变量等都会直接影响到父进程。所以在运行更新环境变量等操作的脚本的时候肯定用的是source这种方式来执行的。另外关于./这种操作方式和其他两种的不同在于,它不是把脚本看成一个文本文件而是一个可操作文件。所以这样做时需要这个文件的执行权限,而其他两种方式都只需要文件的读权限就可以了。
■ yum和rpm的各种命令
rpm -ivh <.rpm> 指定一个包安装
rpm -Uvh <.rpm> 升级一个包
rpm -e <.rpm> 卸载一个包
rpm -q <.rpm> 查询一个包是否安装
rpm -qa 查看所有安装了的包
rpm -qi <.rpm> 列出某个包的信息
rpm -ql <.rpm> 列出某个包内所有文件
rpm -qf <file> 列出某个文件属于哪个包
上面的.rpm可以是一个本地的.rpm文件,也可以是rpm -qa查询出来的一个不带.rpm后缀的包名。
yum的功能是自动从网上寻找、下载并安装一个rpm包,所以所有用yum安装的包都可以通过rpm -qa查到。另外,yum search xxx会列出当前所有源内匹配到的相关包的名称,可以用这个来确定系统到底应该安装哪个包
■ tree是个很方便的命令,不过不是大多数发型版本自带的,需要手动yum install tree安装一下。常用参数有
-L n 只生成n层目录的显示
-d 只显示目录不管文件
-f 显示绝对路径
■ 查询配置文件的时候通常有较多注释和空行,可以考虑cat <file> | egrep -v "(^#|^$)"的方法来只获取有效行
■ 关于重定向的一点简单认识
重定向中几个特殊字符的意义:
0 代表stdin,操作符是<或者<<,以左边的对象文件内容为stdin
1 代表stdout,操作符是>或者>>,将左边内容导入右边
2 代表stderr,操作符是2>或者2>>,意思是将左边的错误信息导入右边
“>>”表示是append而不覆盖之前文件的内容,反之一个>就表示直接覆盖掉之前存在的内容
“<<”右边可以加一个参数,表示终止,即把左边的内容作为stdin读入,读到出现右边内容时终止不再读
通过重定向可以把错误和标准输出(本来是一起输出在屏幕的)分开管理。比如`do some cmd` > outfile 2> errfile 如果需要把stdout和stderr写到同一个文件里面的话可以 >file 2>&1这样来表示。清空文件内容可echo ''>file。如果不需要某个输出的话可以把它重定向到/dev/null设备,它专门用来销毁信息的。
■ 命令复合化
要连续执行多条命令的话第一个想到的就是写一个脚本。其实在逻辑简单的时候,命令行也能搞定。比如:
cmd1;cmd2 顺序结构
cmd1 && cmd2 两者是与关系
cmd1 || cmd2 两者或关系
■ 关于linux上定时工作(工作调度和例行性工作)
1. at命令 一次性的预定工作
at的权限文件在 /etc/at.allow或者at.deny中设置。两者分别采用的是白、黑名单策略。若在这两个文件里面没有设置的话就只有root可以执行at命令
使用at前要先开启atd服务:service atd start
用法:
at [option] TIME
-l 列出所有用户的at工作
-d <jobid> 删除一个at工作
-c <jobid> 列出某个工作的详细信息
TIME的格式是 HH:MM yyyy-mm-dd
at命令不常用,不多说了
2.crontab命令 例行性工作
和at一样,在/etc下有cron.allow和cron.deny。每个用户的cron任务被记录在/var/spool/cron/<用户名>中。crontab的用法:
crontab [-u <username>] [-l/-e/-r]
-l 列出用户的所有cron任务
-e 编辑用户的cron任务
-u 仅root可用,可以指定编辑某个普通用户的cron任务
-r 删除所有cron任务
在用-e进入编辑界面后,每一行都代表一项例行工作,有六个字段,意义为:
分钟(0-59) 小时(0-23) 日期(1-31) 月份(0-12) 周几(0-7,0和7都代表星期天) 命令
时间的参数为*的时候表示该字段的任何时间都接受
带,表示在多个事件点上进行动作
带-表示在一个时间段内。比如20 8-12 就表示从八点到十二点每到X点二十分的时候进行动作
带/n的表示每隔n个单位时间进行动作,比如*/5 8-12 * * *表示每天的八点到十二点间每隔5分钟动作一次。在使用*/n来配置的时候一定要注意,比在当前级别低的时间级别一定要具体成数字来指定。比如想要做每个小时做一次的定时任务,如果配置成* */1 * * *,此时crontab并不知道你这个任务在一个小时的第几分钟做,所以其默认动作仍然是每分钟做一次。也就是说前面那个配置等同于*/1 * * * *。而正确的配置姿势应该是0 */1 * * *,可以将0换成0-59内其他数字,总之具体指定在第几分钟做就好了。
用crontab -e进入的是针对单个用户的crontab任务,如果需要针对整个系统可以编辑/etc/crontab文件。所有crontab的任务的日志会被记录在/var/log下面的cron-xxxx文件中,默认是每周记录一次所以你能看到的只是上周的情况。
● 关于anacrontab和/etc/cron.xxx下的任务
今天在分析一个定时任务的时候,在crontab -l以及/etc/crontab中都没有找到相关的任务设置,但是其确实是发生了。在请教了一通之后发现这个任务的脚本是被放在了/etc/cron.daily目录下。那么这个目录下的脚本为什么会被执行,又是什么时候被执行的呢。
其实这里用到了系统自带的一个程序,anacrontab。anacrontab的主要用途是用来捡漏的。当执行定时任务的时刻到了,而服务器没有开机或处于其他不可执行任务的状态时,这些任务就暂时不被执行而是被记录成Ready状态。anacrontab组件会在合适的时候把这些Ready状态的任务捡起来重新执行。所谓“合适的时候”,一个就是服务器开机的时候,即关机时没能执行的任务在开机之后,anacrontab会调度它们重新执行一下;其他的“合适的时候”就得看anacrontab自己的配置了。先不急着说配置什么,而是来看看ana的工作原理。
每次crontab任务时都会记录任务发生的时间戳,而anacrontab的原理就是检查记录的这个事件戳和当前时间的差距有没有大于crontab固定的任务执行周期。如果大于,则表明在上一次执行此任务到当前这段时间里,此任务有被漏掉执行的情况存在。基于这样一种原理,我们可以看出,anacrontab的作用并不限于捡漏,而可以做更通用的事情(事实上和crontab很类似,可以认为是一个功能稍微更加丰富一些的crontab)再来看配置:
其配置文件在/etc/anacrontab中。打开这个文件我们可以看到:
# /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22 #period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
上面三个配置项就是和/etc/crontab一样的,环境变量的设置。RANDOM_DELAY说明的是通过anacron执行任务时可以设置一个随机的延迟,延迟最大时间以分钟为单位配置在这里。START_HOURS_RANGE指出的是只有在3点到22点间才会去通过anacron执行任务。
重点在下面三行。挑第一行作为例子,1代表anacrontab的检查周期是一天,5代表固定延迟是5分钟,上面提到的RANDOM_DELAY是在这个5分钟基础上再随机延迟一段时间;/etc/cron.daily是一个存放可执行文件的目录,run-parts是个命令,其可以把一个目录下所有可执行文件执行一遍。两者结合起来就是将/etc/cron.daily下所有脚本执行一遍的意思。这个作为一个任务,关联给了这条anacrontab,意思是说当anacron检查到这个任务上一次执行时间距离目前超过了1天的话,就延迟5+random分钟,再执行一次。如果你的服务器是24小时开机的话,那么条anacrontab和直接在crontab中写每隔一天执行一次run-parts /etc/cron.daily是区别不大的,无非这里还有个延迟。
■ grep的正则相关
在linux中,正则表达式分为普通正则和扩展正则。grep处理普通正则式的时候不用特别标识,只要给表达式加上引号即可。但是在grep扩展正则式的时候需要用参数-E指明,告诉系统我grep的是个扩展正则表达式。比如子模式(),统计出现次数的{}等等这些表达方法都属于扩展正则的范畴内
■ 在linux的shell中,双引号引起来的字符串中碰到与bash相关的特殊的可转义字符会转义掉,导致输出中的一些变化。而被单引号引起来的字符串则不对这些字符进行转义(这个单双引号之间的差别和python中单双引号不一样,有点大。。)
比如echo "$1" > testfile后,testfile中并没有内容,因为字符串中的$1被转义了(当初想要批量修改zabbix客户端的配置的时候就吃过这个亏,一下子搞挂了好大一片zabbix客户端服务器。。)而用echo "\$1" > testfile或者echo '$1' > testfile都可以正常的把$1这个字符串echo进testfile中
*另外,一般意义上的字符串的可转义字符比如'\n\t\a'这种,即使双引号也不转义,只有echo -e明确指出需要转义才会转义。
■ 用date命令可以格式化地输出时间,用法是date "+format"(加号一定在引号里面)
format可以自定义一个,比如"%y-%m-%d %H:%M:%S"更多的格式化字符串的参数选项可以参见date --help
date -d <para>可以快速地显示一个时间,比如date -d now ; date -d today ; date -d tomorrow ; date -d yesterday等
设置时间可以通过:
date -s //设置当前时间,只有root权限才能设置,其他只能查看。
date -s 20080523 //设置成20080523,这样会把具体时间设置成空00:00:00
date -s 01:01:01 //设置具体时间,不会对日期做更改
date -s “01:01:01 2008-05-23″ //这样可以设置全部时间
date -s “01:01:01 20080523″ //这样可以设置全部时间
date -s “2008-05-23 01:01:01″ //这样可以设置全部时间
date -s “20080523 01:01:01″ //这样可以设置全部时间
■ 可以通过umask来查看系统的umask值
umask [mode] 可以改变当前用户的umask
创建新目录的时候,创建出来的默认权限是777-umask,而创建新目录的默认权限则是666-umask
比如umask是022的话,目录就是755,文件是644
■ 今天新装了一个台centos7的虚拟机,但是上去之后发现开了一些端口后宿主机却没办法telnet通。
百度了一通之后,发现原因在于防火墙。虽然之前用习惯的centos6.5上也要关闭防火墙(service iptables stop),但是发现在centos7上默认iptables是不开启的,而且开启方式似乎和之前的有点差别。
又百度了一通后发现原来centos7中还带有firewalld.service 这个防火墙,这个是默认开启的,必须关掉才行。命令:
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
另外顺便一提,centos7不自带ifconfig这些命令,需要安装,可以yum search net-tools这个包,这个包里包含了很多网络相关的命令工具。而且centos7中的网卡配置文件以及网卡启动机制有点变化(比如桥接模式的一张网卡在没有network-script下的相关ifcfg-enxxx配置文件的情况下也可以起来)。
■ 就像上条中提到的,CentOS6中的开启关闭服务的方式是service xxx start/stop等,但是放在CentOS7里面就不是了。CentOS7中服务开启关闭要使用systemctl命令。systemctl命令集合老的chkconfig和service为一体,一些常见的操作如下:
systemctl enable xxx #设置某服务开机启动
systemctl disable xxx #取消某服务开机启动
systemctl start/stop/restart #开启/关闭/重启某服务
systemctl reload xxx #重新加载某服务的配置文件
systemctl status xxx #查询某服务状态
systemctl #查看所有服务概况
■ 今天编辑了下vimrc,然后好几次用source /etc/vimrc想把它执行生效,然而老是报错百思不得其解。。后来网上一查才恍然大悟,vimrc特么不是一个环境变量配置文件呐,它的执行是在启动vim时执行的,所以跟source并没有什么关系。。只要改好就好了,下次用vim时会自动生效。。
■ 查看哪个进程打开了某个特定的文件用lsof。详细的参数可以上网查阅。需要注意的是类似于zabbix_server -c zabbix_server.conf这样开启的进程,-c后面的配置文件不属于这个进程打开的文件(只是在开启的时候读取了一下),而可执行文件zabbix_server才是一直被打开着的。
查看某个特定进程打开的是什么文件,可以用ps -ef先确定其进程号,然后进入/proc/<进程号>的目录,查看一些这个进程相关的动态信息,比如cwd文件指向的是进程开启时运行的目录,exe之类的是开启进程真正的可执行文件。
■ 主机名的修改和显示
主机名是网络发展早期主机较少时,期望通过对人友好的一个名字来标识一台主机,本质上是一个字符串和IP地址的关联关系。当然后来主机越来越多,要靠主机名记录下网络中所有主机不显示,所以就催生了DNS体系。但是主机中倒还是一直保留了主机名这个东西,主要用于本地网络和一些小型网络的主机标识。
linux的主机名可以直接通过hostname来显示。hostname <new_hostname>(Centos7中可能是hostnamectl set-hostname <new_hostname>)可以临时性地改变本机的主机名。如果需要永久地改变主机名可以修改/etc/sysconfig/network文件(CentOS系的系统)中的HOSTNAME配置项,以及/etc/hosts文件中127.0.0.1中的localhost.localdomain改成想改的主机名。这样的话就可以使得新主机名永久生效了。
■ 一行命令更改用户密码
echo new_password | passwd --stdin <username>
这条命令的话只有root用户有权限。另外如果是考虑远程或者程序连接过去,不方便敲键盘的话也可以考虑paramiko中的ssh.exec_command中返回的stdin,用stdin.write()来实行改密码操作。
另一个常用的 非交互式改密码的命令是chpasswd:
echo user:new_password | chpasswd
上面这条命令也可以直接一条命令修改密码,user是用户名。虽然看起来chpasswd好像比passwd要高级不少,但是也是普遍存在于一般系统中的,当passwd命令找不到的时候不妨试试找找/usr/sbin/chpasswd来解决
■ yum源的出错处理
今天yum装一个包无论如何装不上去,很是绝望。。后来请同事来处理,发现原来是阿里云的主机只支持阿里云提供的几个有限的yum源,其他的网络都是不通的。yum源都配置在/etc/yum.repos.d目录下面,我也不知道为什么yum不检查所有的源。。总之检查到一个源无法正常连接,然后进入yum.repos.d这个目录把出问题的那个源移除(或者备份到同目录下的某个子级目录中,总之不要让它直接出现在目录下就好了),只留下阿里云支持的两个源,CentOS-Base.repo和epel.repo即可。
再试一下yum,果然可以了
■ 关于linux中硬软链接的一点思考
首先对于一般的文件,文件有inode记录文件的权限信息、时间信息、block指向等。
软链接在实际应用过程中见到的很多了,类比于Windows的快捷方式,软链接的inode指向的block 不是文件内容,而是另一个inode的位置信息。而后者,才是指向文件内容block的inode。当文件被删除,文件自身的inode被删除,对应的block则被标记为已被删除。此时由于软链接就无法找到文件的inode,从而软链接失效。
硬链接则是把一个文件的block,在已经有一个inode的基础上,关联到另一个inode,相当于是创造了一对完全自动同步的文件。删除文件时,会删掉文件的原inode,但是由于文件的引用计数(ls -l时第二字段的值)没有变成0,所以block不标记被删除,通过硬链接依然可以访问文件内容。
从文件系统的结构上来说,软链接是一个类似于引用的东西,引用了某个文件的inode。而硬链接是创造了一个新的文件,但是这个文件的block指向的是源文件的block。
■ 修改命令提示符的样式
默认情况下,发行版本的命令提示符会做一些样式的改变,但是原生Linux下,bash作为shell的命令提示符是长这样的:bash-4.2$。很是不习惯。。命令提示符样式由环境变量PS1控制,只要改变这个环境变量就可以了。如果需要永久地改变这个命令提示符的话自然就要编辑~/.bashrc或者~/.bash_profile这两个文件,然后再source一下就可以了。
比如可在.bashrc文件中加上一行export PS1="[\u@\h \W] \$ "来把命令提示符的样式改变成我们习惯看到的那样。
如果需要在登录时就使环境变量生效(这其实牵扯到.bashrc,.bash_profile,/etc/profile这几个文件的读取规则),记得要确认.bash_profile里面要有source ~/.bashrc。因为登录时不会读取bashrc但是会读取bash_profile。
■ 改变ls的颜色
接上条,(唉其实这两部分内容在玩iPhone的Darwin系统的时候有过记录的,不过那个笔记本不知道被丢到什么地方去了。。)看不习惯的另一点就是ls出来的东西没有按照文件类型分颜色。在很多较高的发行版本中其实root用户都是有这些颜色的,可以直接把这个配置给copy到普通用户那里。
决定ls颜色的是环境变量LS_COLORS,所以把root用户echo $LS_COLORS出来的内容复制到普通用户的.bashrc或者.bash_profile之类的bash配置文件里面去就好了。有几点需要注意的:
1. 配置的内容一定要用单引号,不能用双引号,因为里面含有特殊字符,Linux中双引号的这个坑我就不用多说了吧。。
2. 记得改完后source一下文件立刻生效
3.单单有了LS_COLORS环境变量,ls或者ll出来的可能还是没有颜色的,因为ls命令必须带上--color参数才会读取LS_COLORS这个环境变量。所以没有效果的时候可以试试在.bashrc里面再加上alias ls='ls --color'
■ su user和su - user的区别
su user是直接将当前用户切换成目标用户,而不改变环境。换言之,一切都还是按照当前的环境变量在进行的。如果是su - user的话,相当于把环境变量都换成了目标用户的那一套,等于是重新开了一个会话然后用目标用户登录时得到的那种环境。
■ yum repolist可以查看当前主机上安装过的所有yum的repo
■ 一个命令的某些参数可用不代表这个命令全部参数都可用
比如date命令,一般而言用户都可以调用它来查看当前机器上的时间日期。但是date -s时修改时间日期的命令,不一定对所有用户都开放执行权限。如果要开放则可以通过类似root权限开放其sudo权限的方案来解决。
■ SSH免密登录配置
说起来这是一个非常基础的东西哈,为什么会这么晚才记录都不知道。。
SSH免密登录的原理是这样的:A机想要免密登录B机的userb用户的话,首先A机肯定是一个值得信任的主机,我们不可能让随便一台主机都可以免密登录进来。所以要确认的就是登录请求确实来自于A机。具体实现过程是,首先要在A机上生成一对秘钥,把公钥传输给B机并且放在合适的地方。如此,当从A机发起访问时,可以把访问信息通过私钥加密,然后发送。B机通过公钥解密如果解密出了正确的密文的话,那么自然就可以认为请求确实来自于可以信任的A机。
这一整个过程,具体到Linux中,就是这样的,先执行这条命令:
ssh-keygen -t rsa
这条命令会在执行命令用户的home目录下.ssh目录中(根据RSA算法,-t就是指定算法的参数)生成一对公私钥,名称分别为id_rsa.pub和id_rsa。然后我们需要把前者送给一个目的主机,如果想直接在当前主机的命令行中完成这一操作,那么可以这样:
ssh-copy-id user@10.10.10.10 (B主机的IP)
这条命令将把刚才指出的那个公钥文件的内容自动加入到B主机的,user用户home目录下的,.ssh目录下的authorized_keys文件中去。当公钥存在于这个文件中时,就可以免密登录user用户了。
● 关于known_hosts文件
在.ssh目录下,我们还可以看到一个known_hosts文件,这个文件并不是当前主机作为被登录端时用的,而是作为客户端去登录另一台主机时用的。当我们第一次试图用某用户登录某台主机的时候,SSH协议为了保证安全,需要确认对方是否值得信任,所以它就会展示出对方的公钥信息(公钥很长,显示起来不方便,用的是把对方公钥通过MD5加密后得到的公钥指纹)并且警告你对方是持有这样一个公钥的主机的用户,是否确认要连接?如果选择是,则会把这个公钥加入到本地的known_hosts文件中(这也就是paramiko模块中AutoAddPolicy的本意了)。之后,只要你连接的还是这台主机的这个用户(公钥没变),那么就不会再次警告。这个公钥用于解密对方私钥加密的信息,所以公钥是否可信任也非常重要。
● 一点补充
上述【客户端生成秘钥对】 - 【分发公钥给服务端】 - 【服务端向authorized_keys中添加公钥】 - 【客户端免密登录】的流程是比较规范的。但是也要注意到,免密登录只要求一个秘钥对,至于这个秘钥对是在哪里生成的没有关系。也就是说,完全可以在服务端生成一对秘钥,然后将私钥放到客户端中,再将公钥加入authorized_keys,这样同样可以保持免密。
另外一点,免密登录时默认使用的秘钥文件是.ssh/id_rsa。如果你不小心将这个文件改了一个名字,那么免密就会失效,不过一般客户端都支持指定秘钥文件。比如sftp命令可以通过sftp -i identity_file来指定秘钥,从而保持免密。
■ 升级openssh和openssl【http://blog.51cto.com/hatech/1794520】【https://www.linuxidc.com/Linux/2014-12/110466.htm】
一般的发行版本的系统肯定是自带了openssh用于提供sshd服务的,当前openssh和openssl的版本信息可以通过命令ssh -V来查看。以centos6.5为例,自带的openssh版本为5.3,较老。同时openssl是openssh必须有的一个组件,这个组件也有版本,通常6.5系统带有的openssl是1.0.1e,一个2013年发行的版本,也很老了。升级openssh和openssl看似简单,实际上还是有一些坑的,根据一天更新的情况记录一下。
采用yum install openssh虽然方便,但是由于yum源比较老,安装的版本也都很老,不宜直接使用。但是在后面的安装过程中如果有因误操作导致sshd服务起不来等故障,可以通过yum install openssh来把老版本的ssh重新装回来,可以应急用。
yum不行就考虑用源码编译安装。由于采用源码编译的方式安装组件,所以先到openssh和openssl各自的官网去下载源码包。比如我们这里采用openssh-7.6p1.tar.gz和openssl-1.0.2n.tar.gz这两个包来更新。
首先是上传、解压,在正式开始安装前,可以考虑先开启telnet-server服务。因为升级过程涉及到的是ssh连接,万一把ssh服务搞挂起不来,那么ssh会话一断开就无法重连,必须要到控制台去处理了,挺麻烦的,开启telnet-server的步骤如下:
yum install telnet-server
修改配置文件/etc/xinetd.d/telnet,将disable后的yes改为no,然后在/etc/securetty文件末尾增加几行新的虚拟终端如pts/0,pts/1等。增加的个数一般和需要连接的个数大致一致,如果只是应急重连的话加三个就可以了。
接下来检查一下编译安装过程中用到的一些组件是否安装,如果没安装可以yum install 安装。主要有gcc make perl pam pam-devel zlib zlib-devel openssl-devel
然后先删除老的openssl:
rpm -e `rpm -qa | grep openssl` --allmatches --nodeps
进入openssl的目录,执行命令进行编译:
./config --prefix=/usr --shared
shared这个参数不能漏,否则会引起openssh安装时的报错ssl头不匹配等。
编译完成后依次make,make install进行安装。安装完成后可通过openssl version命令查看当前openssl的版本。
【若采用参考文1中方法没有卸载老openssl,而将openssl装到非系统目录而是/usr/local下面的话需要进行动态库的更新,提一下】
由于openssl会用到一些动态库,所以安装完程序本身之后还要进行动态库的更新。做以下操作:
# 备份老的openssl文件
mv /usr/bin/openssl /usr/bin/openssl.bak
mv /usr/include/openssl /usr/include/openssl.bak # 这是一个目录 # 建立新文件的软链接
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl # 更新动态链接库数据
echo "/usr/local/ssl/lib" >> /etc/ld.so.conf
ldconfig -v # 查看安装后的openssl版本
openssl version
若卸载了openssl,那么可能会遇到一些问题比如yum时报错找不到libssl.so.10,此时可以进入/usr/lib64中,建立两个软链接:
ln -s libssl.so.1.0.0 libssl.so.10
ln -s libcrypto.so.1.0.0 libcrypto.so.10
完成后开始安装openssh,同样先上传解压。停止sshd服务:service sshd stop
先卸载现有的openssh服务,并且将现有的相关文件备份:
# 查看具体包名,可省略
rpm -qa | grep openssh #卸载
rpm -e openssh-server # 备份文件
mv /etc/ssh /etc/ssh.bak
然后进入openssh目录进行编译和安装。注意编译时configure的各个参数。
./configure --prefix=/usr --sysconfdir=/etc/ssh --with-pam --with-zlib --with-md5-passwords
--with-ssl-dir=/usr/local/ssl
(这个参数根据之前openssl的安装情况决定要不要,写什么)
依次make,make install 进行安装。安装完成后可ssh -V查看情况,如果openssh和openssl都已经更新成功的话就ok了、
然后要重新启动sshd服务,由于卸载时一并把系统集成启动脚本给删除了,所以需要把openssh安装包目录下的contrib/redhat/sshd.init文件拷贝到/etc/init.d下并重命名为sshd:
cp /tmp/openssh-7.6p1/contrib/redhat/sshd.init /etc/init.d/sshd (Centos7虽然通过systemctl管理服务,但是也可以这么做)
然后,就是service sshd start重启服务了(Centos7的场合,会自动将这个服务注册进systemctl中)
再运行命令chkconfig --add sshd将sshd加入开机自启动服务中。如此便完成了Openssh和openssl的更新。
更新完成后可能会发现root无法登录,这主要是因为默认的openssh配置中禁止了root通过远程登录。修改/etc/ssh/sshd_config中关于PermitRootLogin的值为yes,重启sshd服务即可。
■ umount时的错误
windows中拔U盘的时候经常会提醒无法卸载硬件之类的错误信息。在linux中也常有这种事。
比如我们要卸载一个挂载在/mnt/test上的硬件(可能是磁盘,光盘,U盘等),报device/target is busy的错的话,可以先lsof | grep /mnt/test/ 来查看到底是什么哪个进程占据这这个目录下的什么内容没有释放,导致的无法卸载。
另一种方法是fuser -m -v /mnt/test/ 加上-v参数很有必要,只有有此参数才会显示出一些内核态的进程。
找准进程杀掉,再卸载就OK了
■ yum超时
不管做什么yum工作都超时,但是可以单独拿出一个yum源然后ping都通。百度上说yum.conf中带有proxy也好,dns没设置好也好,这些问题也都不存在。。
然后google了一下,果然英文资料就是比中文资料NB(不得不承认了。。),发现执行yum --disablerepo=\* --enablerepo=base,updates xxx就可以了。究其原因在于,/etc/yum.repo.d下面有很多非标准的.repo,其中有些文件指向的repo服务器可能已经不再提供服务了,这就导致了不断的超时。
根本的解决办法是将除了标准repo之外的其他repo文件都删除(或者放到同目录下的backup目录中去以防万一),比如阿里云的ECS就只留下Cent-Base.repo以及epel.repo即可。
顺便一提,yum update命令不需要一定在后面更上一个软件包的名字。单纯输入yum update的意思是更新所有可更新的软件包
■ sshd启动失败
今天在阿里云上新买了台机器,但是进入控制台service sshd start之后发生了Generating SSH1 RSA host key Failed的错误。想看日志,但是sshd似乎没有在/var/log/messages中记录,google了一下之后发现通过/usr/sbin/sshd -d命令运行sshd服务的话可以看到详细的DEBUG信息。
详细报错信息为找不到一些/etc/ssh下的文件,一对比果然少了很多dsa_key之类的文件。将其他主机上的复制过去,再重启sshd就正常了。
■ fdisk的使用
我们知道磁盘是作为一种设备文件存在于linux中的/dev/目录下的,而把磁盘和文件系统关联起来要靠mount命令挂载。
今天把磁盘扩容之后按照阿里云的文档重新格式化(不准确,应该是将扩容出来的那部分磁盘给格式化并加入现有磁盘设备)时遇到一个小坑。就是用fdisk命令创建新分区时,后面应该跟整个设备的设备名而不是一个分区名。比如原有的磁盘设备名可能加/dev/vdb1,那么就意味着这个磁盘的名字是/dev/vdb,而1只是表名它是这个磁盘的一个分区(第一个分区,又因为磁盘可能只有一个分区所以vdb1也就代表了vdb,所以df -h看出来的大小什么的都是一样的。这个就比较迷惑了)。fdisk时,要fdisk /dev/vdb,而不是/dev/vdb1!!!
顺便提下如何将新增部分加入现有磁盘分区。在fdisk之前首先umount了当前磁盘并且保证没有程序在使用这个磁盘中的任何数据(lsof /dev/vdb1查看)。然后fdisk,进入命令行,首先输入d删除现有分区(删除分区只是删除逻辑规划,并不是删除磁盘上的数据)
然后输入p创建主分区,如果需要创建多个分区那么就需要在主分区之后再创建几个拓展分区,那时输入e。
然后输入n表示新建。随后会要求指出新建分区从哪个cylinder开始到哪个结束。如果是只建立一个分区那么就可以使用默认值(1号cylinder开始,最后一个结束)。
最后输入wq保存新建分区,如果没报错就好了。再把/dev/vdb1给mount回去之后,df -h检查下容量是否增加了,增加了就完成了。
■ su失败并不一定意味着用户无法登录
今天用普通用户su root,无论用什么姿势输入密码都是拒绝登录。。一直以为密码输错了,但是后来发现原因是普通用户在/bin/su的group的执行权限位上没有s权限,加上之后(chmod +s /bin/su)就好了。
密码没有错,通过ssh直接连接root用户是没有问题的。
■ whereis命令
linux上的应用通常都会按照配置,可执行文件,脚本等分成多个部分部署安装在系统的不同地方。虽然有些潜移默化的规范告诉我们大概什么文件会放在什么地方,偶尔还是很难记起来。
whereis命令辅助帮忙找可能的安装位置。可以尝试一下。
■ yum和yum源
yum是CentOS系统重要的包管理工具。由于会自动处理依赖关系,比较方便,所以被广泛使用。
yum的主配置文件是/etc/yum.conf。一般而言这个文件的内容不需要怎么变更,直接用默认的即可。在这个文件中可以看到一些配置如默认的日志是/var/log/yum.log,默认的缓存目录是在什么地方,是否对下载的包进行缓存等等。
重要的是看到这个文件位于最后一行的注释,说明了我们应该将一些附加的repo即源放在/etc/yum.repos.d里面。在这个目录下,有很多.repo文件,这些文件中配置了各个源的信息。以系统自带的最基本的源配置文件CentOS-Base.repo为例:
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
.repo文件中往往会有很多这种类似的配置section。一个section其实对应的就是一个配置好的源。一个repo中往往有很多个源,主要是为了适配比如不同系统版本,不同软件版本引起的依赖库不同的情况。就一个section而言,其各个参数的含义如下
base(option名) option的名字就是这个源的名称。必填项。另外不同的repo文件之间允许有相同名称的源出现。此时yum程序会帮助我们寻找一个合适的源进行操作。也就是说相同名字的源最终只会用到一个。
name 这个属性是源的标识名,可以不写
baseurl 指出了一或若干个镜像服务器的地址,实际上我们要下载的包存放的地方。baseurl和最上面的option名是一个源配置的两个必填项。也就是说配置一个源最基础的只需要有这两个参数即可。
mirrorlist 镜像服务器有很多很多,有时候不同的镜像服务器之间下载速度会差很多。mirrorlist提供的地址类似于一个服务,可以根据你提供的参数给出一个相对较快的镜像服务器列表,而yum会在其中找到一个合适的进行下载。显而易见,mirrorlist和baseurl不需要同时设置。这也是为什么我们这边把baseurl前面加了#注释掉的原因。
enabled 当设置为1时表示该源启用,为0时禁用。如果配置中未设置enabled项那么默认是1。
gpgcheck 是否开启gpg校验,1为是,0为否。所谓gpg校验是一种校验下载包是否就是原包的手段,和给出md5值类似。gpgkey就是gpg检查用到的一些凭证了。
下面再补充几条yum的命令
yum repolist 可以查看目前repos中一共配置了哪些repo以及这些repo的详细信息如repo名,标识名,内含包量等等
yum list xxx 可以查看到当前这些源中可以下载到的某个包,又有哪些包已经安装了。支持*通配符。比如yum list libtiff*。和yum search相比可以更加精确地控制匹配。
yum info xxx 可以查看某个包的详细信息
yum remove xxx 卸载不是uninstall是remove
yum makecache和yum clean all yum在一段时间内首次进行安装时,会把repo的信息给缓存到本地从而提升接下来yum的速度。makecache就是手动来生成这些缓存,clean则是清除缓存
另外顺便说下,如果在yum update之类批量总的操作时,如果想要指定几个不升级,可以使用--exclude=xxx,比如yum --exclude=openss* update,就可以避免更新openssh和openssl等组件
■ 编译wget时参数
修复wget的一个漏洞的时候,要升级版本到1.19以上。但是源码编译安装报错no package gnutls found,应该是gnutls版本不够导致
在编译的时候加上--with-ssl=openssl可以免除这个问题。即./configure --prefix=/usr --sysconfdir=/etc --with-ssl=openssl
■ 磁盘总使用空间与目录总大小不符 && 被打开的文件
某一个磁盘挂载在/test目录,df -h命令发现其使用量已经达到99G,但是执行下du -sh /test发现总量加起来不过也才60多G。
后来发现前一天有人试图清理/test下内容,删除了一些文件。不过这些文件被应用进程打开着。删除之后虽然文件系统中已经找不到这个文件了,但是这部分文件占用的磁盘空间并没有被释放。
通过lsof命令可以查看到当前系统被打开的所有文件。对于那些被打开但是却也被删除的文件,每个文件最后会加上(deleted)的后缀,把这些文件对应的进程给杀掉就好了(当然服务的话就是重启就好了)。
也就是说lsof | grep deleted基本上就可以看到哪些文件已经被删除但是没有释放磁盘空间的了。
其实这个现象也说明了在应用开发过程中,处理完文件之后进行文件句柄的关闭是很重要的。比如我们在python shell中open一个文件,此时lsof中会有这个文件。然后在另一个shell窗口删除此文件。此时lsof可以看到文件名后面有了deleted标志。此时文件的标记已经从系统中移除,但是由于进程还没有关闭句柄,有可能会读文件,所以内容并没有被标记删除(操作系统中删除文件并不是用0重写文件占据的磁盘空间,而是将这块磁盘空间标记为不再使用)。换句话说,此时程序尝试读文件比如print f.read()还是可以读取到内容。如果程序关闭了文件句柄如f.close(),此时lsof就看不到这个已经被删除的文件了。同时其占据的磁盘也被真的标记不再使用,或者说得到真正的释放了。
■ 关于ulimit
ulimit是一个shell的内置程序(所以虽然在字符界面中可以使用ulimit命令,但是which ulimit是看不到具体的程序的,因为被包括在bash里面了),用于对用户的shell做出一些限制比如最大打开文件数,最大线程数等等。
ulimit -a 命令可以看到各种ulimit的相关指标以及值。而ulimit -x (x是一个具体的参数)可以看到各个值,比如ulimit -n就是查看当前shell的最大文件打开数。如果在后面再跟上一个数字,那么就是修改这个参数值了。比如ulimit -n 2048就是将最大文件打开数调整为2048个。
在实际使用过程中,ulimit可能会出现拒接接受修改的情况。这种情况出现的第一可能是/etc/security/limit.conf文件中没有做好对ulimit可修改的最大值的规定。具体的修改方法可以谷歌一下。不过一般情况下,系统中的这个文件里肯定会有 * soft nofile 65535和* hard nofile 65535,这表明任何用户ulimit -n xxx后面接的数字可以直接写最大的65535而不会出错。
然而有时候还是会出错,这很可能是因为sshd服务启动时的配置项UseLogin设置是no。 此时sshd启动不去读取/etc/pam.d/login文件,而这个文件又会指出需要读取limits.conf文件。因为前者没有被读取,所以后者自然不会生效。因此,所有通过ssh登录并打开的shell中,ulimit -n都是无法修改的。相对的,如果是另外方法打开的shell,比如su - xxx进入的xxx用户的shell,此时很可能会看到ulimit -n和单纯ssh登录上来的不太一样,并且可以通过ulimit -n xxx修改。