shell 命令

Table of Contents

1. 获取命令帮助

任何 shell 书籍或者文档都不可能覆盖命令的所有参数使用,在 Linux 中,当需要更多命令帮助时,请使用 man 和 info。

man 是简短的帮助文档,GNU 觉得 man 比较落后而开发了 info,info 具备超链接,以及一些开发文档,内容更加丰富,多数时候通过 man 只能获得大致信息,更详细的可以用 info 查看,所以 info 可和 man 起互补作用。pinfo 是具备 lynx 浏览器风格的 info。

1.1. man

通常会看到一些文档上提示使用man参考帮助信息,格式如:ls(1)。

括号里的数字叫“章节编号”,例如 stat(1) 和 stat(2) 虽然名字一样,但代表了不同的帮助,具体的章节号信息,通过 man man 可以找到。

1.1.1. 搜索

-k:按关键字搜索帮助,如:

$ man -k search

whatis 命令也搜索手册的概述,可以用通配符、正则。

1.1.2. 更新 man 库

man 中的文档是由 mandb 命令更新。在 crontab 下有一个自动更新的脚本,默认系统会每天自动更新:

/etc/cron.daily/man-db.cron

如果库更新失败,在用 man -k 搜索时就会出错:

$ man -k passwd
passwd: nothing appropriate.

这种情况直接手动运行 mandb 命令更新即可。

1.2. 其他命令

help:Bash 内置的命令,语法帮助,注意 zsh 中没有该命令。

2. shell 控制

Ctrl+z 可以让当前进程挂到后台继续运行,前台恢复 shell 交互式状态。

jobs:列出后台运行的进程

fg:让后台运行的进程回到前台

$ jobs
[1]  - suspended  vim
[2]  + suspended  emacs -nw

# 如果后台存在多个进程,参数 %num 可以指定进程
# 如果不带参数,默认恢复最后一个
$ fg %2                         # 把 Emacs 恢复到前台,不指定参数

suspend:把当前 shell 挂载到后台,典型应用场景是用 su 进入了 root 的 shell,然后临时想回到普通身份又不想关闭 root shell:

$ echo $UID
1000
$ sudo su
[root@ ~]# echo $UID0
0
[root@lx-pc ~]# suspend # 将当前 shell 放到后台运行
[1]  + 204721 suspended (signal)  sudo su
$ echo $UID
1000
$ jobs # 可以看到 root shell 在后台运行
[1]  + suspended (signal)  sudo su

3. 进程

3.1. ps

# 显示所有进程
# a:显示所有进程
# x:显示当前用户的进程
# u:显示用户
ps aux

# 展示进程的父子关系:
ps --forest

ps -ef

# 如果用户名太长,会用“+”代替超长的部分,如下第一列用户名:
# systemd+     858  0.0  0.0  25704 10520 ?        Ss   14:08   0:05 /usr/lib/systemd/systemd-resolved
# 指定 ruser 格式为任意一长串字符即可:
ps -o ruser=xxxxxxxxxxxxxxxx -e -o pid,ppid,c,stime,tty,time,cmd

3.2. pgrep

搜索进程ID

3.3. coproc

shell 提供的协程功能,让命令在新生成的子 shell 中执行。

“&” jobs fg

3.4. kill

# 向指定 PID 的进程发送信号,-9 表示杀死进程
kill -9 pid

# 向进程组发送信号:
kill -SIGINT -- -组ID

4. 文本处理

4.1. fgrep、egrep 和 grep

fgrep 只匹配字符,egrep 使用了扩展正则表达式,现在都整合到了 grep 里,分别通过 -F、-E 参数区别。

# 从文件 file 中查找 keyword
grep keyword file

4.2. fmt格式化输出

如下文本:

All material created by James Mohr is copyrighted 1994-2003 by James Mohr and is licensed under a modified GNU Free Documentation License. Reproduction and distribution of material copyrighted by James Mohr or derivative of such material in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder. Distribution of substantively modified versions of material copyrighted by James Mohr is prohibited without the explicit permission of the copyright holder. Distribution of material copyrighted by James Mohr in a commercial product is prohibited without the explicitpermission of the copyright holder. Use of material copyrighted by James Mohr in any commercial endeavour is prohibited without the explicit permission of the copyright holder. A "commercial endeavour" includes, but is not limited to training or other educational courses for which a fee is required. Public education institutions (such a state universities and colleges, community colleges and similar) are except from this requirement and need only

执行后:

All material created by James Mohr is copyrighted 1994-2003 by
James Mohr and is licensed under a modified GNU Free Documentation
License. Reproduction and distribution of material copyrighted by James
Mohr or derivative of such material in any standard (paper) book form
is prohibited unless prior permission is obtained from the copyright
holder. Distribution of substantively modified versions of material
copyrighted by James Mohr is prohibited without the explicit permission
of the copyright holder. Distribution of material copyrighted by James
Mohr in a commercial product is prohibited without the explicitpermission
of the copyright holder. Use of material copyrighted by James Mohr in any
commercial endeavour is prohibited without the explicit permission of the
copyright holder. A "commercial endeavour" includes, but is not limited to
training or other educational courses for which a fee is required. Public
education institutions (such a state universities and colleges, community
colleges and similar) are except from this requirement and need only

可以指定 -w 参数设置每行行宽。

4.3. expr

执行表达式,包括正则匹配、四则运算等。

例1,字符串按下标取子字符串

expr substr "abcd" 1 2          # => ab

例2,使用正则判断 IP 地址

expr match "192.168.1.1" "^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$" # => 11

使用正则时要注意“{”、“}”、“(”、“)”需要转义,详细见:info expr

使用小括号配对时,打印匹配的值:

expr match "192.168.1.1" "^\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)$" # => 192.168.1.1

4.4. seq

# 打印列数,例:
seq 3
# 输出:
# 1
# 2
# 3

# 指定分割符、输出结果不换行,适合生成序列
seq -s ',' -w 10                # => 01,02,03,04,05,06,07,08,09,10

4.5. paste

按列合并两个文件

假如文件1:

1
2
3

文件2:

a
b
c

执行合并:

$ paste 1 2
1	a
2	b
3	c

paste 默认使用 Tab 作为分割符号,参数 -d 后面跟字符自定义分隔符。使用空格话,需要转义空格字符,如:

$ paste 1 2 -d\
1 a
2 b
3 c

4.6. tr

转换、替换和删除字符

# 删除文件中的空字符(NULL)

# 文件内容如下:
# $ hexdump /tmp/has_00
# 0000000 6261 6300
# 0000004

$ tr -d '\0' < /tmp/has_00 | hexdump
0000000 6261 0063
0000003
# 按字符集替换
$ echo 'luanx' | tr '[al]' '[41]'
1u4nx

替换换行符:

# Unix 换行符转 Windows 换行符
tr '\n' '\r\n'

4.7. head/tail

head:打印文件头部内容

# 显示文件前 n 行内容,默认 n 为 10
head file

tail:打印文件尾部内容

# 显示末尾 n 行内容,默认 n 为 10
tail file

# 打印文件倒数 5 行
tail -5 /etc/passwd

# 跳过文件前 10 行的内容,即从第 11 行开始打印
tail -n +10 /etc/passwd

4.8. pr

在文本顶部加上title和页码,便于打印。

4.9. nl

nl 命令可以给文本每行开头加入行号

如:

$ cat x
test1
test2
test3
$ nl x
1  test1
2  test2
3  test3

4.10. shuf

从文本中随机抽取行数打印。

shuf 文件名 -n1

-n:随机显示1行

4.11. xargs

  • 它用于格式化数据流
  • 它可以转变数据流内容成程序参数

以下是测试源文件 test:

1
2 3
4 5 6
  1. 默认上数据流变成行
cat test|xargs:
1 2 3 4 5 6
  • 参数 -d 还可以指定分隔符
  • 参数 -n 指定每行最多列数
$ cat test | xargs -n 2
1 2
3 4
5 6
  1. 递归删除文件
find . -name '.svn' | xargs rm -rf

4.12. tac

连接并逆序输出文本,示例:

$ echo -n 'a\nb\nc\n' | tac
c
b
a

4.13. tee

可以将内容同时输出到两个地方,从标准输入读入数据并输出到标准输出以及文件中。

例,读入数据并写入到其他文件中:

cat /etc/hosts | tee /tmp/hosts.bak

例,把输出的内容用sudo追加到文件中:

echo -n "127.0.0.1\twww.baidu.com" | sudo tee -a /etc/hosts

要用echo xxx > /etc/xxx 这种需要 root 权限的来说,得这样:

echo xxx | sudo tee --append /etc/xx

4.14. less/more

# 翻屏查看文件内容
less file
# 翻屏查看文件内容,但不可向上翻屏
more file

5. 文件相关

5.1. 查找文件位置

which:显示命令的绝对路径

例:

which cd                        # => /usr/bin/cd

对于 alias,which 也能显示出来:

$ which ls
ls='ls --color=auto -F'
	/usr/bin/ls

command 命令可以达到相同效果,并且 command 是 POSIX 标准中的命令:

command -v ls                   # => alias ls=exa

whereis:查找文件、man和源码的路径

$ whereis cd
cd: /usr/bin/cd /usr/share/man/mann/cd.n.gz /usr/share/man/man1/cd.1.gz /usr/share/man/man1p/cd.1p.gz

5.2. ls

# 列出当前目录下文件
ls

# 列出指定目录下的文件
ls /path

# 列出 home 目录下的文件
ls ~

# -l 参数会显示详尽的信息
ls -l

5.3. mv

# 将文件/目录重命名或移动到指定的目录中
mv file target

5.4. pwd

# 获得当前目录绝对路径
pwd

5.5. cat

# 查看文件内容:
cat file

# 输出行号:
cat -n /etc/passwd

5.6. find

# 找出最近创建的文件:
# 参数 mtime,表示最近 n×24 消失修改过的文件
find ./ -mtime 0

# 查找 SUID 的程序
# -perm 指定权限位,如 -perm -777
find 目录 -perm -4000

# 找出指定日期之后创建的文件:
find . -name '*.doc' -newermt 2017-04-20

# 删除文件名乱码文件:
# 有时删粗文件时,遇到文件名乱码,并且shell无法补全的情况下,就可借助find命令来删除。
# 1、获取文件的 inode:
ls -i
# 2、按 inode 号查找,并删除:
find . -inum inode号 -exec rm {} \;

5.7. rename

常用于批量重命名文件。不同的发行版 rename 命令版本不一样,有些是 C 版本,有些是 Perl 版本。

Fedora 默认是 C 版本的,Ubuntu 默认是 Perl 版的。

C 版本的 rename 接受三个参数:

rename 要修改的字符串 替换后的字符串 文件列表

# 例,将图“1.jpg、图2.jpg...”重命名为“1.jpg、2.jpg...”:
rename '图_' '' *.jpg

Perl 版的 rename 可直接写正则表达式,例如某目录下有以下文件:

$ ls
2016-08-01  2016-08-02  2016-08-03

将它们批量重命名为“yyyyMMdd”格式:

rename 's/\-//g' 2016*

结果如下:

$ ls
20160801  20160802  20160803

5.8. ss

显示 socket 状态

5.9. comm

对比两个已排序过的文件

对比两个都已排序过的文件

comm file1 file2

结果分成 3 行,第一行是文件 1 中出现过的行,第二行是文件 2 出项过的行,第三行是文件 1 和文件 2 共同出项过的。

另外有两个参数:

  • 1 不显示第一个文件出现过的
  • 2 不显示第二个文件出现过的
  • 3 不显示共同部分

comm -12 file1 file2:显示 file1 和 file2 共同行,即求两个数据集的交集。

5.10. strings

打印文件中的可见字符。

上次遇到 Nginx 配置文件误丢,但 Nginx 还在运行,可用 gcore 命令将进程数据 dump 出来,再用 strings 把内存中的配置信息找出。

5.11. cd

切换目录。

# 切换到当前目录下的子目录
cd sub_dir

# 切换到指定目录
cd /path

# 切换到 home 目录
cd ~

小技巧:CDPATH 环境变量

设置常用路径,使用 cd 命令时,可以不用写完整路径。

5.12. rm

# 删除指定文件,默认需要按“y”确认
rm file

# 不经确认删除文件
rm -f file

# 删除目录
rm -r dir

# 技巧1,删除指定目录所有文件,并排除某些文件:
rm -rf `ls | grep -v 文件名`
# 或者
rm -rf `ls | grep -v '[1|2|3].php'`

5.13. mktemp

新建临时文件,随机生成临时文件名。

5.14. mkdir

# 新建目录
mkdir dir_name

5.15. 解决“-”开头的文件名

方法1:如果对文件名使用了“-”开头使用 cp、mv、rm 命令,用“–”参数即可:

# 例,删除名叫“-exec”的文件
rm -f -- -exec
mv -- -exec new
cp -- -exec new

方法2:可以用 ls -i 获得 i 节点号,然后用 find 命令操作。

方法3:最简单,直接带上路径,如:mv ./-exec a,即可。

5.16. dd

命令非 Unix 风格,dd 的命令风格来自JCL(https://en.wikipedia.org/wiki/Job_Control_Language

磁盘写入速度测试:

sync; dd if=/dev/zero of=test_file bs=1M count=1024; sync

5.17. split

对文件分割,例如将一个 4,000 行的日志分割为 4 个 1,000 行的文件:

split -l 1000 access.log

5.18. read

交互式输入:

read name
echo $name

6. 系统相关

6.1. arch,查看处理器架构

arch                            # => x86_64

6.2. date

日期字符串和时间戳之间转换:

# 获得当前时间戳
date +%s                        # => 1461552157
date -d'2016-04-25 14:23' +%s   # => 1461565380

# 时间戳转字符串
date -d @1461551881             # => 2016年 04月 25日 星期一 10:38:01 CST
# 自定义格式
date -d @1461551881 +'%Y-%m-%d' # => 2016-04-25

# 日期计算:
date -d '-1years'               # => 2015年 04月 25日 星期六 10:56:09 CST
date -d '-1days'                # => 2016年 04月 24日 星期日 10:56:13 CST
date -d '-1months'              # => 2016年 03月 25日 星期五 10:56:16 CST

# 例,遍历某段时期的日期:
start_date=20151101
end_date=20171126

while [[ $start_date < $end_date ]]
do
    echo $start_date
    start_date=$(date -d "+1 month ${start_date}" +%Y%m%d)
done

6.3. time

time 命令可以统计一个程序的执行总时间、在用户以及内核模式的执行总时间

如:

time python test_case.py

# 执行结果:

# Ran 1 test in 2.326s

# OK

# 0m2.372s
# 0m0.044s
# 0m0.008s

这里可以看到执行完这个 Python 脚本所花的总时间,user 和 sys 分别是用户态和内核态执行的总时间,user+sys 的时间与 real 的时间相差较大的话,说明I/O阻塞所花费的时间比较长。sysuserreal

6.4. lsof

# 查看进程打开的 socket
# 例,遇到 urllib2 的一个坑,文档说不用手动关闭,而 close 方法却是个 pass
# 在多线程+高并发请求网页时候,会阻塞死,以下命令可以看到大量的连接请求:
lsof -i tcp:80

# 查看文件/目录被哪些进程操作
lsof 目录/文件名

# 查看进程使用了哪些文件
# 如果要查看多个进程,使用多个 -c 参数就可以了
lsof -c 进程名

# 如果要按 PID 查看:
lsof -p PID

# 查看进程占用了哪些端口:
lsof -Pl +M -p [PID]

# 或者根据端口号查找进程:
lsof -Pl +M -i4 -i6  | grep [端口号]

6.5. chsh

#更改用户的默认 shell:
sudo chsh -s /bin/zsh lu4nx

6.6. watch

# 周期性执行某个命令。
# 例,实时监控 dmesg:

watch "dmesg | tail"

6.7. env

# 显示当前环境变量
env

6.8. iotop

I/O 监控版 top 命令

# 只显示当前有 I/O 操作的进程(不显示线程):
iotop -oP

7. 网络相关

7.1. curl

# 发送 GET 请求
curl http://webserver

# 下载文件
curl -o [filename] http://webserver

# 路径中保持“../”:
curl --path-as-is

7.2. wget

# 下载文件
wget http://webserver/filename

7.3. ssh

# 登录到指定服务
ssh username@host

# 指定证书文件
ssh -i 证书路径 username@host

7.4. ip

现代发行版用 ip 取代了 ifconfig。

# 查看各网卡的 IP 地址
ip addr

8. 压缩解压

# 将文件 file1、file2 打包到 file.tar 中
tar cvf file.tar file1 file2

# 解开压缩包
tar xvf file.tar

# 用 ZIP 格式压缩文件
zip file.zip file

# 解压 ZIP 文件
unzip file.zip

9. 图像相关

9.1. display

# 显示图片
display img.jpg

10. 其他

10.1. bc

echo 1+1 | bc                   # => 2
echo '1*0' | bc                 # => 0,注意有“*”存在,所以要加引号
echo '4/2' | bc                 # => 2
echo '4-2' | bc                 # => 2

# bc 可以指定进制,例,二进制计算:
echo 'obase=2;ibase=2;01+10' | bc # => 11