放假的电话

命令行常用工具

命令行工具,不会用虽然不是不可以,但是生产力确实大打折扣。给自己定下个小目标,每天刻意学一些,希望能帮助提高工作效率。

由于用的是Mac,下面的命令跟linux并不一定完全相同,但是多数应该是差不多的。

grep

grep是一个pattern search的工具,有几个变种:

  1. grep: 适合基本的正则表达式
  2. egrep: 适合扩展的正则表达式, 相当于grep -E
  3. fgrep: 比之前2个都快,但是不能用正则, 相当于grep -F

zgrep, zegrep, zfgrep分别对应上面的3种,但是可以用于压缩文件。

grep的所有参数可以参考man,下面列出一些比较好用的。


1
2
# 搜索hello
grep hello example.txt
1
2
# -Cnum,显示搜索结果的前后num行匹配,注意之间没有空格
grep -C3 hello example.txt
1
2
# -c, 显示包含匹配的行数,注意,哪怕一行中有多个匹配,也只算一行
grep -c hello example.txt
1
2
3
# -d,对directory的处理。默认是read,也可以设置skip跳过directory, 或者recurse递归。recurse的效果跟-r一样.
# 在当前目录递归搜索hello
grep -d recurse hello .
1
2
# -e,使用正则表达式, 搜索Hello或者hello, 同时也适用于搜索的东西带‘-’的情况
grep -e '[Hh]ello' example.txt
1
2
3
# --exclude,不搜索满足匹配的文件, include与之相反
# 在当前目录递归搜索hello,不搜索所有js文件
grep -r --exclude \*.js hello .
1
2
3
# --exclude-dir,不搜索directories, include-dir与之相反
# 在当前目录递归搜索hello,不搜索test文件夹
grep -r --exclude-dir test hello .
1
2
# -i,case insensitive
grep -i hello example.txt
1
2
3
# -H,显示匹配的文件名,在搜索目录时会比较有用
# 在当前目录递归搜索hello,case insensitive,输出文件名和匹配的行
grep -riH hello .
1
2
3
# -l,显示带匹配的文件名。由于只要有1个匹配就会停止,操作比较节省。-L与之相反,显示不含匹配的文件名
# 在当前目录递归搜索hello, case insensitive, 只输出匹配的文件名
grep -ril hello .
1
2
3
# -n,显示行号
# 在当前目录递归搜索hello,insensitive,输出文件名和行号
grep -rinH hello .
1
2
# -s, silent,不输出error
grep -s hello example.txt
1
2
3
# -x, 如果一整行满足匹配,才输出, 例如grep hello, 只有hello单独一行的情况才会输出
# 搜索单独的一行hello
grep -x hello example.txt
1
2
3
# -v, 输出的行是不满足匹配的行
# 输出不带hello的行, case insensitive
grep -vi hello example.txt

cat

cat 是一个输出/拼接文件内容的工具

1
2
# -n, 输出行号
cat -n example.txt

1
2
3
# 拼接文件
# 把file1 file2的文件拼接,输入file3
cat file1 file2 > file3

cp

cp 用于复制文件,平时最多就是加个-R,但是其实还有几个比较好的参数

1
2
# -R, 递归拷贝
cp /var /tmp/var

1
2
3
# 遇到已经存在的文件时,有3个参数-f, -i, -n实现控制
# -f强制重写,-i询问用户,-n不重写
cp -Rf /var /tmp/var
1
2
# -p, 保留文件的修改时间等信息
cp -p file file2

curl

curl算是一个比较常用的命令了。虽然有很多UI工具可以做更多更方便的事,但是有些简单的命令,用curl会效率更高。而且,curl真的很强大!高级用法估计可以单独写一篇,这里就单单写一下常用的

1
2
# -A <agent string>, 设置user agent
curl -A 'Mozilla/4.0' www.google.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# -d data, post 数据,相当于 --data data。
data的类型有下面几种:
content
=content
name=content
@filename
name=@filename
# 向http://test 提交firstName和lastName
curl --data "firstName=test&lastName=Shen" "http://test"
# 如果数据来自文件,可以用@file
curl --data @file 'http://test'
# 最后,如果要提交的是来自文件的所有binary内容,用--data-binary
curl --data-binary @file 'http://test'
1
2
3
4
5
# -b <name=data>, 读取cookies。如果没有=,那么就把它当做是个文件名,从文件中加载cookies
curl -b 'name=test;name1=test1' www.google.com
# -c <filename>, 保存cookies。如果filename是dash “-”, 输出到stdout
curl -c - www.google.com
1
# -D <filename>, --dump-header, 保存header
1
# -G, --get, 把--data的数据变成get请求,而不是post
1
2
# -H, --header, 添加header
curl -H 'Content-Type:text/plain' www.google.com
1
2
3
# -i, 在输出内容的同时,输出header
# -I, 只请求header!如果只需要header,这个参数节省带宽
1
2
# -u <user:pwd> 携带用户名和密码
curl -u minwei:test www.google.com
1
2
3
# -L, 如果server返回3xx,表示资源需要跳转,curl会根据新的地址自动重新发请求
# 有load balancer的情况下可能特别适用
curl -G -d 'customer=123&limit=3' example.com -L

find

find命令递归遍历指定目录。通过额外的参数,在遍历每个文件时,进行filter。最常用的莫过于搜索文件。

1
2
3
# -iname pattern, 搜索文件, case insensitive
# 在当前目录递归搜索md文件
find . -iname "*.md"

less

1
2
3
4
5
# 向下翻页
spance, f, j, d
# 向上翻页
b, k, u
1
2
3
4
5
# 给当前位置作mark,记为<letter>
m<letter>
# 跳转到mark <letter>
'<letter>

ls

ls命令显示文件夹内容, 常用的参数如下

1
2
3
4
5
6
# -a, 包含.开头的目录
# -F, 在路径最后添加/,在可执行文件最后添加*,等等
# -h, 与-l同时使用,给文件大小添加K,M,G等单位
# -R, 递归显示子目录内容
# -l, long format,显示更多信息
# -r, 逆序(如果用某个参数排序了的话)

ls提供了不少参数,给显示的文件排序,可以结合-l, -r使用:

1
2
3
4
# -S, by size
# -t, by modified time
# -u, by last access time
# -U, by creation time

ls -l显示的文件权限信息,第一位表示是否是directory。之后,每3个一组,分别表示user,group,others的权限。

regular expression

tar

1
2
3
4
5
6
7
# 压缩
tar -zcvf file.tar.gz directory
# 其中
# -z, gip压缩
# -c, create
# -v, verbose
# -f, 指定文件名
1
2
3
4
# 解压缩
tar -xzvf file.tar.gz
# 其中
# -x, 解压缩

awk

awk也是一个处理text的工具,跟sed类似,awk也是按行处理的。下面只列举我觉得最好用的,更多的参数、用法有需要再学吧。

1
2
3
# -F, 指定分隔符
# echo 'a:b:c:d' | awk -F: '{print $1}'
a

awk的$n默认是从1开始的

1
2
3
4
5
6
7
8
9
10
# ls -l | awk '{print $1 "\t" $9}'
-rw-r--r--@ _config.yml
-rw-r--r--@ db.json
drwxr-xr-x@ node_modules
-rw-r--r--@ package.json
drwxr-xr-x@ public
drwxr-xr-x@ scaffolds
drwxr-xr-x@ source
drwxr-xr-x@ themes
-rw-r--r--@ urls.txt

bg, fg, ctrl-z, & and jobs

在命令行后面加&,可以让一个任务在后台执行。但是,如果你忘记了怎么办?或者想把一个任务放到后台,怎么办?可以这么做:

1
2
3
# ctrl + z ,suspend当前任务
# bg, 让任务在后台执行

下面的命令可以显示所有任务

1
2
3
4
# jobs, 显示所有任务
[1] Running bash download-file.sh &
[2]- Running evolution &
[3]+ Done nautilus .

要把任务放到前台,或者kill任务,使用:

1
2
# fg %1, 恢复第一个任务
# kill %1, kill第一个任务

sed

sed是unix里的一个流编辑器,简单实用,但是非常强大

1
2
3
4
# s,替换。下面的例子把day换成night
echo Sunday | sed 's/day/night/'
sed 's/day/night/' old_file > new_file

注意, sed的替换默认每次只会处理一行的1个匹配。如果1行中有多个匹配,默认只有第一个会处理。

有的时候,sed要替换的东西里带/,这么一来需要转义,就比较麻烦。实际上,sed的分隔符不是必须用/,也可以使用_:或者|。只要不出现在使用的正则匹配中就可以。

1
2
3
4
5
6
# & 表示实际匹配到的字符
echo "123 abc" | sed 's/[0-9]*/& &/'
# 输出 123 123 abc
# 对于上的例子,如果要使用扩展的正则表达式,要用参数-E。+就是扩展的正则表达式中才支持的。
echo "123 abc" | sed 's/[0-9]+/& &/'

正则表达式可以用转义的()来捕捉匹配,并通过\1\2之类来使用捕捉的匹配。

1
2
# 只保留每行的第一个单词
sed 's/\([a-z]*\).*/\1/'

在sed的最后一个分隔符后面,可以加参数

1
2
# /g,处理每一行的所有匹配
sed 's/day/night/g' old > new

sed默认会打印每一行输入,使用参数-n不打印。但是,如果我们又要看匹配的结果,使用/p

1
echo sunday | sed -n 's/day/night/p'