shell命令:文件与进程
我的读书笔记,学习shell的强大的文件进程管理命令。
书名 | 作者 | 下载地址 |
---|---|---|
Classic Shell Scripting | Arnold R. & Nelson H.F.B | 暂无 |
Advanced Bash-Scripting Guide | Mendel Cooper |
ls
列出文件列表,等价于windows的dir
ll命令列出当前的文件属性
[root@www ~]# ls -l
-rw-r--r-- 1 root users 6845 Jun 25 08:53 install.log
# 输出结果格式化一下,如下表:
-rw-r--r-- | 1 | root | users | 6845 | Jun 25 08:53 | install.log |
---|---|---|---|---|---|---|
0123456789 | link | owner | group | size | access date | filename |
注释
0:文件类型:
- d:目录
- -:文件
- l:链接
- b:ram设备
- c:串行设备
1~9:拥有者权限,所属群组权限,其他人权限
权限掩码,看这里
link:文件硬链接数或目录子目录数,在这里看看
chgrp:改变文件所属群组
chowm:改变文件拥有者
chmod:改变文件权限(suid,sgid,sbit)
以上三个命令都要求改变后的用户或群存在于系统中/etc/passwd或group
chmod 可以使用数字形式或者符号形式:
chmod 777 filename
chmod a+x filename
其中a+x格式化一下:
a | + | x |
---|---|---|
1 | 2 | 3 |
注释
- 1:可选u g o a分别对应拥有者(user),组(group),其他用户(others),全部(all)
- 2:可选+ - = 分别对应加入,除去,设定
- 3:可选r w x分别对应读写执行
显示当前的文件夹名称:
pwd
显示当前文件夹绝对路径,加上-P 参数
pwd对应系统变量PWD
@ruanyf的奇淫技巧:有关显示目录的命令:
只显示普通目录,不显示隐藏目录
ls -d */
ls -F | grep /
ls -l | grep ^d只显示隐藏目录,不显示普通目录
ls -d .*/
显示所有目录,不显示文件
find -maxdepth 1 -type d
ln
实现文件符号链接,硬链接。相当于windows的mklink
ln [-sf] 来源文件(夹)src 目标文件(夹)dest
选项与参数:
-s :通常采用符号链接,如果不加任何参数就进行连结,那就是hard link,-s 就是symbolic link,
-f :如果 目标文件 存在时,就主动的将目标文件直接移除后再创建!
注意【SRC】和【DEST】需要写全绝对路径,否则提示
Too many levels of symbolic links!
建立软链接就是建立了一个新文件。当访问链接文件时,系统就会发现他是个链接文件,它读取链接文件找到真正要访问的文件。建立硬链接会获得与原文件等同的地位。
博客上面ls命令提到的第二个字段link的含义如下:
一、如果是一个普通文件:
那么这一字段表示,这个文件所具有的硬链接数,即这个文件总共有多少个文件名.查看第一个文件:
-rw-r--r-- 1 root root 1581 11月 24 18:14 aaa.cfg
第2字段的值为1,说明这个文件只有aaa.cfg这一个文件名.即只有一个指向该链接的硬链接.
如果我用ln,做一个指向该文件的硬链接再查看该文件,该搜索文件的第2字段就会变成2:
[root@ubuntu]# ln aaa.cfg aaa.cfg.hardlink
[root@ubuntu]# ls -l
总用量 4071
-rw-r--r-- 2 root root 1581 11月 24 18:14 aaa.cfg
-rw-r--r-- 2 root root 1581 11月 24 18:14 aaa.cfg.hardlink
此时,aaa.cfg 和aaa.cfg.hardlink 称为互为硬链接.他们指向同一个文件,无论是修改哪一个文件,另一个里也做相应的变化,因为实际上他们指向同一个文件.
可以查看它的文件节点(inode)
ls -i aaa.cfg
互为硬链接的文件具有相同的文件节点. 以下是验证实验:
[root@ubuntu]# ls -i aaa.cfg
18102 aaa.cfg
[root@ubuntu]# ls -i aaa.cfg.hardlink
18102 aaa.cfg.hardlink
可以看到,这两个文件具有相同的文件节点号:18102
如果你知道一个文件有多个文件名,如何查找他的其他文件名分布在什么地方呢?
可以先用ls -i 获得它的节点号,然后用find查找,若具有多个文件名,我要查找与它互为硬链接的文件:
[root@gucuiwen devices]# ls -i /etc/sysconfig/networking/devices/ifcfg-eth0
147181 /etc/sysconfig/networking/devices/ifcfg-eth0
得到它的节点号为 147181,再用find查找:
[root@ubuntu]# find /etc -inum 147181
/etc/sysconfig/networking/devices/ifcfg-eth0
/etc/sysconfig/networking/profiles/default/ifcfg-eth0
这样就得到了同一个文件的不同文件名的位置.
二、如果是一个目录:
link字段表示该目录所含子目录的个数.
新建一个空目录,这个目录的第二字段就是2,表示该目录下有两个子目录.有一个指向它本身的子目录"." 和指向它上级目录的子目录"..",这两个默认子目录是隐藏的.用ls -a可以看到.
每次在目录下新建一个子目录,该目录第2字段的值就增1,但是新建一个普通文件该字段值不增加.
cd
经典的命令,(Change Dir)
建议配合使用压栈出栈的方式cd:
cd ~
pushd .ssh/
# 这样打开了.ssh文件夹,并把上一次的位置入栈
popd
# 返回到~,出栈了
find
搜索当前文件夹,并以ascii顺序排序结果:
find | LC_ALL=C sort
搜索文件夹,使用ls的风格显示结果,以第11个字段【文件名】进行排序
find -ls | sort -k11
寻找"o"开头的文件,排除目录:
find 'o' -type f
搜索我的目录下大于1MB的文件:
find /home/ubuntu -size +1024k
搜索大小在1k~1M的文件:-a代表AND逻辑与,同样-o代表OR
find . -size +1k -a -size -1024k
搜索空文件:
find . -size 0
搜索符号链接
find -L /var/www/ -xtype l
其他选项:-ctime是inode变更时间,-atime访问时间,-mtime修改时间。
寻找文件,类似的命令 locate,支持通配符搜索
还有个很实用的命令:type 能搜索到当前命令的别名,类型,还有指向位置
type cd && type gcc && type ll && type foorbar
cd is a shell builtin
gcc is /usr/bin/gcc
ll is alias of ‘ls -alF’
sh: type: foorbar: could not found
还有个常用的命令:file,判断文件类型
file /etc/passwd
# /etc/passwd: ASCII text
file /tmp/sogou-qimpanel-cell
# /tmp/sogou-qimpanel-cell: socket
file /dev/sda
# /dev/sda: block special
在文件中查找字符串:(Finds string in files)
grep -rnw '/home/ubuntu' -e "pattern_to_find"
xargs
防止A命令的结果为空时,作为参数输入到B命令出错。
例如下列命令,当搜索不到结果时会使得grep报错:
grep POSIX /dev/null $(find /usr/include -type f)
使用xargs防止这种错误发生,遇到空结果时候不执行grep:
find /usr/include -type f | xargs grep POSIX /dev/null
df
是Disk Free的缩写。查看磁盘分区用量
使用-h (human-readable)查看简洁的摘要:
df -h
#结果
文件系统 容量 已用 可用 已用% 挂载点
udev 3.9G 4.0K 3.9G 1% /dev
tmpfs 788M 1.3M 786M 1% /run
/dev/sdb5 4.8G 1020M 3.6G 22% /
none 4.0K 0 4.0K 0% /sys/fs/cgroup
none 5.0M 0 5.0M 0% /run/lock
tmpfs 512M 128M 385M 25% /run/shm
类似的命令是du (Disk Usage),告诉你的磁盘用量
du /tmp
# 结果
4 /tmp/.ICE-unix
52 /tmp/.org.chromium.Chromium.ucrnZv/html
12 /tmp/.org.chromium.Chromium.ucrnZv/css/viewer-toc
16 /tmp/.org.chromium.Chromium.ucrnZv/css/column
同样支持 -h (huaman-readable)选项。
du的原理就是深入查找文件,将每个文件空间求和输出。
diff
比较文件,git里面也是集成了一个diff,感觉比系统自带的好用,因为有彩色显示。这里就不介绍git diff了。
使用diff的惯例:把旧文件作为参数第一个。
# 1.txt文件
hello world
i am tony
i live in China
# 2.txt文件
hello world
add a line
I am Tony
Now I am sleepy
执行比较
diff 1.txt 2.txt
# 结果
2,3c2,4 # 表示旧文件的2~3行发生变化(c符号),变成新文件的2~4行
< i am tony # 左箭头表示旧文件
< i live in China.
--- # 分隔新旧文件
> add a line # 右箭头代表新文件
> I am Tony
> Now I am sleepy
c代表change a代表add d代表delete。
建议使用-u参数,接近git diff的输出风格:
diff -u 1.txt 2.txt
# 结果
--- 1.txt 2016-01-22 19:12:27.838666220 +0800
+++ 2.txt 2016-01-22 19:12:41.914666098 +0800
@@ -1,3 +1,4 @@ # 原文件的1~3行在输出结果前面3行
# 新文件的1~4行为输出结果是结果除去掉减号内容
hello world
-i am tony
-i live in China
+add a line
+I am Tony
+Now I am sleepy
patch
执行由diff命令比较结果的改动,自动完成差异更改。通常用于程序员之间交流代码,很方便的对同一份代码进行比较修改。
diff -c old.txt new.txt > /tmp/patch.dif
cp old.txt /tmp
cd /tmp
patch < patch.dif # 这个patch直接对源文件生效,改动覆盖原文件
cat old.txt
patch尽可能地套用不同之处,然后报告失败的地方,由你手动处理
pgp
通常下载完毕,首先检验md5:
md5sum ubuntu.iso
但是并不能保证是发布者原封不动的发布的,当黑客改动文件,并把改动后的MD5发布到网站上,也能进行欺骗,所以引入GPG签名保证文件是签名是正确的。
在更新ubutnu软件包时,开发者首先公布他的pgp公钥,然后让用户下载。
wget -O- http://shadowsocks.org/debian/1D27208A.gpg | sudo apt-key add -
pgp这部分暂时没资料,不过感觉和openssl一块用进行加密是完全可以的。
kill
PID:进程id
PPID:父进程id
相关命令: pgrep pkill trap
pgrep netscape # 寻找netspace的PID
pkill -HUP netspace
pkill -TERM netspace
pkill -KILL netspace
# 上面三个命令不建议,因为进程名称不是唯一的。误杀。
使用kill杀死进程 pid
trap
假设有个脚本,模拟后台运行:trap语句被触发:当后面的信号到达时
# loop.sh
#! /bin/sh
trap 'echo ignoring HUP' HUP
trap 'echo Terminating on USR1; exit 1' USR1
while true; do
sleep 2
date > /dev/null
done
执行:
sh ./boop.sh &
# 24444
kill -HUP 24444
# Ingoring HUP
kill -USR1
# Terminating on USR1
[1] + Done(1)
试试向他发出其他信号:
sh ./loop.sh &
# 22222
kill -CHLD 22222
jobs
[1] + Running sh ./loop.sh &
kill -PIPE 22222
[1] + Broken Pipe ./loop.sh &
原来一个broken pipe信号就杀死他了。。
试一下默认的kill信号:
sh ./loop.sh &
# 11111
kill 11111 # 默认是TERM信号
[1] + Done sh ./loop.sh &
经过我的无数次实验,发现使用trap被触发后,调用trap前的一条命令会被退出,然后执行trap所在那行的命令:
# 1.sh内容
#! /bin/bash
trap 'echo in trap..; sleep 5; exit(0)' 2 # 信号2代表SIGINT就是Ctrl+C
2.sh
# 2.sh内容
while true; do echo from 2.sh!; sleep 1; done
实验过程:
在A终端执行1.sh,屏幕不断输出from 2.sh,另外开一个终端B
ps aux | grep 2.sh
发现有2行输出(2.sh 和 grep auto 2.sh),在A终端按Ctrl+C,触发trap命令。接下来5秒时间内,可以在终端B执行上面这句ps aux发现已经没有2.sh的进程了。证明了我的猜想。
umask
umask值一共有4组数字,其中第1组数字用于定义特殊权限,我们一般不予考虑,与一般权限有关的是后3组数字。
默认情况下,对于目录,用户所能拥有的最大权限是777;对于文件,用户所能拥有的最大权限是目录的最大权限去掉执行权限,即666。因为x执行权限对于目录是必须的,没有执行权限就无法进入目录,而对于文件则不必默认赋予x执行权限。
对于root用户,他的umask值是022。
当root用户创建目录时,默认的权限就是用最大权限777去掉相应位置的umask值权限,即对于所有者不必去掉任何权限,对于所属组要去掉w权限,对于其他用户也要去掉w权限,所以目录的默认权限就是755
当root用户创建文件时,默认的权限则是用最大权限666去掉相应8421权重的umask值,即文件的默认权限是644
Q:如果将umask值设为0003,那么此时创建的目录或文件的默认权限是多少?
A:正确的结果应该是:目录的默认权限是774,文件的默认权限是664。在计算默认权限时,不是用十进制的最大权限直接减去umask值,要以二进制考虑。将umask值所对应的相应位置的权限去掉,这样才能得到正确的结果。