文件_bash笔记3

UNIX系统把一切都看作文件,甚至命令终端也是和一个设备文件关联在一起的,可以通过向该文件写入来实现向终端写入信息,例如:

# 输出到当前终端
echo hoho > /dev/tty

# bash环境,发送到连接在ttys001端口的终端上
echo hoho > /dev/ttys001

dd

用来生成指定大小的文件,常用于硬盘读写测速

// 生成测试文件test.data
// 填充\0,大小为10M
dd if=/dev/zero of=test.data bs=1024 count=10k

// 写硬盘测速
// 对磁盘进行连续写入,不使用内存缓冲区,每次写入8k的数据,总共写入4k次,产生32M大小的文件
dd bs=8k count=4k if=/dev/zero of=test.data conv=fdatasync

// 读硬盘测速
dd if=test.data of=/dev/null bs=4k

if是输入文件(input file),of表示输出文件,bs写入块的大小。/dev/zero是特殊设备,用来产生无限多的\0字符,dev/null是空设备,输入的东西都丢掉

P.S.mac下conv参数没有fdatasyncfsync选项

comm

comm命令用来对比文本文件,实现diff。但输入必须是有序的文件,所以一般结合sort使用:

# sort命令的-o选项表示输出到文件,这里直接替掉原文件
sort a.txt -o a.txt; sort b.txt -o b.txt
# 做diff
comm a.txt b.txt

P.S.wget-o-选项长得很有意思,表示Get as a file and print the result on STDOUT

会得到3列结果,分别是:

# a有b没有的 b有a没有的 ab都有的
    a差b       b差a     a交b

有这3列就能恢复a文件和b文件(有序的,排序之前的无法恢复),比如a=a差b并a交b

-1/-2/-3选项删除指定的列,选项必须出现在输入文件前,例如:

# 去掉第三列,不输出a交b
comm -3 a.txt b.txt

# 把ab的差异合并到1列,结果是ab有差异的行
comm -3 a.txt b.txt | sed $'s/\t//g'

特别注意:正则表达式前面的$取值运算,不加的话匹配不到制表符,与IFS=$'\n'同理

P.S.Mac下sed -i文件原地替换相当麻烦,必须指定备份文件名(虽然可以是空串)

diff

用来生成差异文件,例如:

# u选项输出更常见的格式,写入diff.txt
diff -u a.txt b.txt > ab.diff

按行比较文件,得出新增了哪些行,删除了哪些行(修改操作等价于新增新行删除旧行),结果类似于:

--- a.txt    2017-03-15 10:50:34.000000000 +0800
+++ b.txt   2017-03-19 16:56:14.000000000 +0800
@@ -1,6 +1,11 @@
+
+end yaya
 data
-end
 is
-line
 no
+line
 this
+
+newend
+line

diff结果给a和b打补丁就能得到b和a:

# 给a打补丁
patch -p1 a.txt < ab.diff
# ab的内容相同
md5 a.txt; md5 b.txt

要恢复原内容的话再patch一次:

# 补丁回来
patch -p1 a.txt < ab.diff

也能对文件夹做diff

# N不存在的文件视为空文件,a所有文件视为文本文件,r递归比较子目录
diff -Naur data files

mkdir

用来创建文件夹,如果已经存在,就返回错误:

mkdir: bak: File exists

一般需要检查:

# 如果不存在的话,创建
if [ ! -e path ]; then mkdir $path; fi

对于深层路径,逐级检查比较费劲,可以简单丢弃错误:

mkdir ./dir1 2>/dev/null
mkdir ./dir1/dir2 2>/dev/null
mkdir ./dir1/dir2/dir3 2>/dev/null

更简单的做法是:

mkdir -p ./dir1/dir2/dir3

忽略已经存在的,创建需要创建的

文件权限

常见的3类权限:

  • user:文件的owner

  • group:用户组

  • others:除user和group用户外的用户

ls -l列出的文件权限格式为:文件类型(1位)user权限(3位)group权限(3位)others权限(3位)

文件类型如下:

- 普通文件
d 目录
c 字符设备
b 块设备
l 符号链接
s 套接字
p 管道

后面的3位权限每位取值有4种:-rwx,分别表示无/读/写/执行

P.S.如果文件权限是----------的话,表示除root外的所有用户都没有权限处理该文件,无法读写执行

另外有3种特殊权限,会出现在x的位置:

  • setuid:允许用户以owner权限来执行文件,比如-rws------

  • setgid:允许用户以owner所在组权限来执行文件,比如----rws---

  • sticky bit:粘滞位,只有创建该目录的用户才有权限删除下面的文件,其它用户即便有写权限也删不了,比如-------rwt

注意:st都有大小写两种,区别是s表示有x权限,S表示没有x权限

修改权限

chmod命令,例如:

# 设置权限
chmod u=rwx g=rwx o=rwx test.sh
# 添加user执行权限
chmod u+x test.sh
# 添加所有执行权限
chmod a+x test.sh
# 删除user权限
chmod u-x test.sh

也可以用数值来设置权限:

# 等价于u=rwx g=rwx o=rwx
chmod 777 test.sh

777是3组rwx二进制表示对应的十进制数,比如r--为4(100

P.S.一般把这个叫八进制值(值为0到7都不超过8?),实际上二进制解释更合理

设置3个特殊权限也用chmod

# setuid, setgid, sticky bit
chmod u+s
chmod g+s
chmod o+t

用数值设置的话,在3种权限前添一组sst,例如chmod 2777 test.sh中的特殊权限是2(010),也就是-s-表示setgid权限

修改所属权的命令是chown

# 设置属于user1用户,属于staff组
chown user1.staff test.sh

一般配合setuid权限使用:

# root组root用户
chown root.root bomb.sh
# 如朕亲临
chown u+s bomb.sh

touch

touch摸一摸,存在的话更新时间戳,不存在的话创建一个空文件:

# 存在的话,更新所有时间戳为当前时间
touch test.sh
# 存在的话,只更新访问时间
touch -a test.sh
# 存在的话,只更新修改时间
touch -m test.sh

head/tail

只查看文件内容的某一部分,例如:

# 看前10行
head test.sh
# 看前3行
head -n 3 test.sh
# 不看后10行
head -n -10 test.sh

# 看后10行
tail test.sh
# 看后3行
tail -n 3 test.sh
# 不看前90行(输出第91行到结束)
seq 100 | tail -n +91

P.S.Mac下-n参数不能是负数,会报错head: illegal line count -- -10

ls只列出目录

有3种方法:

# d选项最简洁
ls -d */
# F添上类型标识,筛选/结尾的
ls -F | grep "/$"
# l选项结果以权限开头,权限以类型开头,筛选d开头的
ls -l | grep "^d" | awk '{print $9"/"}'

也可以用find

# 按文件类型查找
find . -type d -maxdepth 1 -mindepth 1 -print

注意depth范围,只找下一级

路径切换

经常用cd -cd $OLDPWD)返回上次工作路径,实际上还有更强大的:

# 与cd作用看似相同
pushd /tmp
# 查看历史路径栈(-v编号)
dirs -v
# 返回上一次工作路径
pushd
# 返回上上一次...
pushd +1
# 返回上上上一次...
pushd +2

pushd用来切换工作路径,交换栈顶记录与指定记录,但历史栈长度不变,需要删除记录的话,用popd

# 返回上一次工作路径,并删除当前路径
popd
# 删除上上一次工作路径
popd +1
# 清空历史栈(只保留当前记录)
dirs -c

+N-N表示方向,+N从栈顶开始数0123...-N从栈底开始数

P.S.注意og my zsh某个版本+-方向是反的,bash正常

wc

统计行数、单词数、字符数,常用于简单的代码统计:

# 输出行数、单词数、字符数
wc test.sh
# 取行数
wc -l test.sh | awk '{print $1}'
# 取单词数
wc -w test.sh | awk '{print $1}'
# 取字符数
wc -c test.sh | awk '{print $1}'

P.S.数单词的功能很弱,空格隔开的字符串就算一个单词,也不区分标点符号

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code