Linux 常用命令

1 切换用户(switch user)

对于 Ubuntu 来说:

  • 切换至 root 或其他普通用户:
    默认情况下,刚安装的操作系统虽然有 root 用户,但是没有为 root 用户设置一个固定的密码(提供的是一个随机的密码),因此首先需要为 root 用户创建一个固定的密码。
    sudo passwd root
    然后键入需要设置的密码。另外,如果想要改变 root 密码,也可以执行这个命令。

    然后就可以切换至 root 了。
    su -l
    切换至 root 后,提示符为 #

    -l 表示新打开的 shell 以一个登录 shell 的形式读取环境变量。

    上面默认是切换至 root,如果想切换到其他用户,则用 su -l 用户名

  • 从 root 或者其他普通用户切回切:
    exit
    或者
    ctr + d

    切换至普通用户后,提示符为 $

注意:为 root 用户设置好密码后,可以通过 sudo passwd -l root 锁定 root 用户,此时再想用 su - 切换至 root 时,会提示认证错误。对于锁定了的 root 用户,可以用 sudo passwd -u root 来解锁。

对于 CentOS 来说,会在安装操作系统的时候提示用户输入 root 密码,因此在命令行中切换至 root 直接用:
su -l

切换至普通用户同 Ubuntu。

2 图形界面与文字界面的切换

切换至文字界面:
ctr + alt + f1~f6
登录 tty1~tty6 终端界面。

切换至图形界面:
ctr + alt + f7
也即登录 tty7 图形界面。

注意:Linux 提供了 7 种运行等级,一般用到的是 run level 3 和 run level 5。前者可以使用 tty1~tty6 的文字界面;后者不仅可以使用 tty1~tty6 的文字界面,还可以使用 tty7 的图形界面。

如果要让系统启动时使用某种界面,那么只需要修改 /etc/inittab 这个文件中的 default run level 即可。在 Centos 中,用相关命令进行修改。

在 Ubuntu 中,则在 /etc/init/rc-sysinit.conf 这个文件中进行修改。

3 关机与重启

将系统的服务停掉后关机:
shutdown -h now
或者
shutdwon -h 0

将系统的服务停掉后重启:
shutdown -r now
或者
reboot

在某一个时刻关机:
shutdown -h 15:10 "将在 15:10 关机"

在某个时间段之后关机:
shutdown -h 10 "将在 10 分钟之后关机"

取消正在进行的 shutdown 命令:
shutdown -c

4 /etc/passwd 与 /etc/group

/etc/passwd 中保存了所有用户的相关信息(每行保存一个用户的信息),以 : 号分开。比如:
cuckootan:x:1000:1000:Jason,,,:/home/cuckootan:/bin/zsh

其中:

  • 第一个字段为用户的名字,用以登录;
  • 第二个字段是用户密码(该字段为 x,真正的密码信息存储于 /etc/shadow 之中);
  • 第三个字段是用户的 ID;
  • 第四个字段是用户的主组 ID(或者叫用户的初始登录组 ID);
  • 第五个字段是用户的全名,不能用以登陆;
  • 第六个字段是该用户的起始目录,用户登录过程中打开 登录shell 或者之后打开一个 非登录shell 时,将使用这个目录作为当前工作目录;
  • 第七个字段是 登录shell,指用户登录时打开的 shell(终端文字界面)。(事实上,在图形界面下点击终端图标打开的 shell 也是这个 shell)。

/etc/group 中保存了所有用户组相关信息(每行保存一个用户组的信息),以 : 号分开。比如:
sambashare:x:128:cuckootan,haha
其中:

  • 第一个字段表示用户组名字;
  • 第二个字段表示用户组密码(同上,相应的信息存在 /etc/gshadow 中);
  • 第三个字段是用户组的 ID;
  • 后面则是这个组中的所有用户,以 , 号分开。

5 添加 / 更改 / 删除一个用户

添加一个普通用户:
sudo useradd -g 主组名 -G 附加组1,附加组2,...,附加组n -d /home/xxx/xxx -s /bin/zsh username
其中,-s 指定 登录shell。

删除一个普通用户:
sudo userdel username

更改一个普通用户(设置所有附加组为列出的附加组):
sudo usermod -g 主组名 -G 附加组1,附加组2,...,附加组n -l newusername -s /usr/sbin/nologin username
其中,/usr/sbin/nologin 表示该账号不能用作登录主机。

更改一个普通用户(追加列出的附加组为这个用户新的附加组):
sudo usermod -g 主组名 -a -G 追加的附加组1,追加的附加2,...,追加的附加组n -l newusername username

6 添加 / 更改 / 删除一个普通用户组

添加一个普通用户组:
sudo groupadd groupname

删除一个普通用户组:
sudo groupdel groupname

更改一个普通用户组:
sudo groupmod groupname

7 查看与改变用户所在组

查看某个用户所属组列表(包括主组和附加组):
groups 用户名

注意:一个用户可能属于多个组。/etc/passwd 中每个用户后面的那个用户组是这个用户的主组。

建立一个 shell子进程,并改变当前用户所在组(不会改变 /etc/passwd 文件):
newgrp - groupname

改变之后的组必须是当前用户所在的主组或附加组。由于是建立的 子shell,因此改变只能在 子shell 中有作用,对它的 父shell 无作用。要永久改变用户所在组(也即改变 /etc/passwd/ 文件),需要用 usermod 命令。

8 修改用户密码

修改普通用户密码:
passwd 普通用户名

修改 root 用户密码:
passwd root

这是在系统成功启动后的终端中执行的。如果说因为忘记了登录密码而不能登入系统之中,那么就只能通过另外的方法重置密码了。参见:使用 Grub 进入单机模式进而修改 root 或普通用户密码

9 sudo 命令与 sudo 组

用 su 命令切换到某个用户时,会创建一个新的 shell。如果再在其基础上执行命令,则不会对之前的环境变量造成影响,这在很多情况下是不方便的。

sudo 命令在执行某个命令时,会临时获取 root 用户或者其他用户的身份,而无需创建一个新的 shell。

一般用法为:
sudo -u username -H command
表示以 username 用户身份执行 command 操作。

如果省略 -u username,则默认以 root 用户执行 command 操作。
另外,-H 表示将 \$HOME 设为 username 的初始工作目录。

sudo 还可以用来切换到其他用户:

1
2
3
4
# 切换至 root.
sudo -i
# 切换至 username
sudo -iu username

与 su 的区别在于,用 su 切换至其他用户时,需要指定相应用户的密码;而 sudo 需要指定当前用户的密码。

只有加入到 sudo 组中的用户(成为 sudoer)才能执行 sudo 命令:

加入到 sudo 的方法为:

  • 首先切入到 root。
    su -
  • 打开 /etc/sudoers 文件。
    visudo
    该命令专门用于打开 sudoers 文件。

    一般情况下,默认的文本编辑器为 nano,如果要改成 vim,则执行如下:
    sudo update-alternatives --config editor
    然后选择 /usr/bin/vim.basic 或者 /usr/bin/vim.tiny 或者 /usr/bin/vim.nox 即可。

  • 然后在
    root ALL=(ALL) ALL
    后面添加:
    username ALL=(ALL:ALL) ALL

    其中,第一个 ALL 是 *Hosts,表示允许执行 sudo 命令的主机;
    第二个 ALL 是 RunAsUsers 的值,表示允许 username 以任何用户的身份执行某个命令;
    第三个 ALL 是 RunAsGroups 的值,表示允许 username 以任何用户组的成员的身份执行某个命令;
    第四个 ALL 是 Commands 的值,表示 username 可以执行 secure-path 中各个路径下的所有命令。

    如果想用 sudo 在任何时候执行命令时都无需验证密码,则可以加上 NOPASSWD: 字段。例如:
    username ALL=(ALL:ALL) NOPASSWD: ALL

    如果想将某个组的用户都加入 sudo 组,则加上如下字段:
    %group ALL=(ALL:ALL) ALL

另外,可以通过如下命令查看当前用户的 sudo 权限:
sudo -l

如果要查看某个特定用户的 sudo 权限,则使用:
sudo -lU username

10 切换目录

切换至主目录:
cd

切换至根目录:
cd /

切换至父目录:
cd ..

切换至操作过的上一个目录:
cd -

切换至当前目录下的 dir 目录:
cd ./dir

cd 是 shell 内部命令,因此调用它不需要建立 子shell,直接调用即可,因此才可以改变当前的工作目录。

11 查看当前目录的绝对路径

pwd

12 拷贝文件或目录

将 src_filename 这个文件拷贝到 des_dirname 目录(若之前存在)下。
cp PATH_1/src_filename PATH_2/des_dirname

将 src_filename 这个文件拷贝到 des_dirname 目录下,并重命名为 src_filename_2(若之前不存在)。
cp PATH_1/src_filename PATH_2/des_dirname/src_filename_2

将 src_dirname 这个目录拷贝到 des_dirname 目录(若之前存在)下。
cp -r PATH_1/src_dirname PATH_2/des_dirname

将 src_dirname 这个目录拷贝到 des_dirname 目录下,并重命名为 src_dirname_2(若之前不存在)。
cp -r PATH_1/src_dirname PATH_2/des_dirname/src_dirname_2

其中:

  • -r 用以递归地进行目录下所有文件的拷贝。
  • 对于已存在的同名文件,默认覆盖它们,没有提示信息。
  • -i 用以对已存在的同名文件提示是否需要覆盖。
  • -n 表示不覆盖存在的同名的文件。
  • -u 表示如果存在同名文件且源文件比目标文件更新时才会发生覆盖。或者是目标文件不存在时,也会发生拷贝。
  • -f 表示如果已存在的同名的文件打不开,则强制删除它们再进行拷贝(这个参数好像是默认启用的)。
  • -f -i-n 不能同时使用。
  • -b,若目标目录下存在与源文件名同名的文件或与源目录同名的目录,会先进行备份(备份的文件或目录名后有个 ~ 符号),然后进行移动。

注意:cp 命令只是拷贝源文件或者源目录中的所有文件到目标目录下,如果目标目录中原来有一些与源文件和源目录中的某些文件不同的文件,拷贝结束后,这些文件依旧存在,不会删除。

13 远程拷贝文件或目录

用法和 cp 差不多,只不过对于远程的文件或目录,需要在前面加上用户名,地址。比如:
scp PATH_1/src_filename username@ip:PATH_2/des_filename

14 移动文件或目录(也可用于更改文件名或目录名)

移动 src_filename 这个文件到 des_filename 这个目录(若之前存在)下。
mv PATH_1/src_filename PATH_2/des_filename

移动 src_filename 这个文件到 des_filename 这个目录下,并重命名为 src_filename_2(若之前不存在)。
mv PATH_1/src_filename PATH_2/des_filename/src_filename_2

移动 src_dirname 这个目录到 des_dirname 这个目录(若之前存在,且其中没有名为 src_name 的目录,或者有但是为空的目录)下。
mv PATH_1/src_dirname PATH_2/des_dirname

移动 src_dirname 这个目录到 des_dirname 这个目录下,并重命名为 src_dirname_2(若之前不存在)。
mv PATH_1/src_dirname PATH_2/des_dirname/src_dirname_2

其中,也有一些常用的参数:

  • 对于已存在的同名文件,默认覆盖它们,没有提示信息。
  • -f,对已存在的同名文件,强制覆盖,没有提示信息(这个参数好像是默认启用的)。
  • -i,对已存在的同名文件,则提示是否需要覆盖。
  • -n,不覆盖已存在的同名文件。
  • =u,如果存在同名文件且源文件比目标文件更新时才会发生覆盖。或者是目标文件不存在时,也会发生移动。
  • -b,若目标目录下存在与源文件名同名的文件或与源目录同名的目录,会先进行备份(备份的文件或目录名后有个 ~ 符号),然后进行移动。

注意:不能用一个目录覆盖同名但不为空的目录,具体原因不详。因此,对于目录的移动,一般先确保目标目录下没有与源目录同名的目录存在或者存在与源目录同名的空目录,然后再进行移动。

另外,移动发生的操作并不是先拷贝再删除,而是在目标目录中添加一个新的目录项,使得这个目录项中的 inode编号 为源文件的 inode 编号(发生硬链接),然后再删除源文件。

15 删除文件或目录

删除文件:
rm filename

递归删除目录下所有的文件:
rm -r dirname

其中:

  • 默认情况下,删除一个存在的文件时,没有提示信息。
  • -i 参数在每删除一个文件时都会提示。因此在删除文件或目录时,为了安全起见,一般会带有这个参数。可以用 aliasrm -i 定义别名。
  • -f 参数在指定的文件不存在时,不会报错(这个参数好像是默认启用的)。

16 清空文件

echo -n "" >filename
或者
cat /dev/null >filename

17 显示目录中的所有文件

对该目录下的所有非隐藏文件(隐藏文件是指文件名第一个字符是 . 的文件)按行显示,每行显示一个文件的属性,按文件名排序:
ls –l

注意:如果参数后面没有添加目录名,则表示默认显示当前目录下的所有文件。如果添加了目录名,则表示显示这个目录下的所有文件。

  • 其中,第一个字段是文件方式(或者文件权限,具体为读,写,可执行)。首字符如果是 d,则代表该文件是个目录文件,如果是 -,则代表该文件是普通文件,如果是 l,则代表该文件是符号链接文件,如果是 p 代表管道文件,如果是 s,则代表该文件是 socket 文件,如果是 b,则达标该文件是块设备文件,如果是 c,则代表该文件是字符设备文件。后面的字段中,前面 3 个是该文件所有者(即后面的第三个字段)对这个文件的权限,中间 3 个字符是文件所属组(即后面的第四个字段。文件所有者可以在这个组中,也可以不在这个组中)中的每个用户(如果文件所有者也在这个账号中,则表示除文件所有者之外这个组中的其他用户)对这个文件的权限,后面 3 个是既不属于文件所有者也不属于文件所属组的其他用户对这个文件的权限。
  • 第二个字段是该文件的硬链接计数(... 这两个特殊的目录文件也有对应的硬链接计数)。
  • 第三个字段是文件拥有者。
  • 第四个字段是文件所属组。
  • 第五个字段是文件的大小,以 B 为单位。对于目录文件,显示的仅仅是它本身的大小(它的各个目录项),并不是对这个目录文件递归求和得到的总大小。
  • 第六个字段默认是显示最后一次修改文件内容(打开文件,并写文件)的日期和时间(mtime,modification time)。对于某个文件,若创建之后没有修改文件的内容,则显示的是创建日期和时间。另外,如果要显示最后一次状态修改(也即是文件属性的修改)时间(ctime,change time)以及最后一次访问文件内容时间(atime,access time),则分别加上 -c 以及 -u 参数。
>   注意:所谓的状态修改,表示文件的 inode节点 中信息的修改。只有当 mtime 后者 atime 或者 inode节点 中的其他字段发生变化时,ctime 才会发生变化。
>   

>   另外,文件内容的修改一定会变更 mtime 和 ctime(因为 inode节点 中的文件长度信息改变了),但不一定会变更 atime。比如:
    `echo "hello" >>file.txt`
    或者
    `echo "hello" >file.txt`
    它们只是打开文件,读取 inode节点 到内存,然后获取首个数据块的地址以及文件长度,从而就知道文件所在数据块的首地址以及尾地址,不需要读入文件内容到缓冲区中。因此也就不会变更 atime。
    而用 vim 打开文件时,需要将该文件的所有内容读入到内存之中。

>   值得注意的是,即使访问过文件内容,也不一定改变 atime。自 Linux 2.6.30 开始,ext4 文件系统挂载到目录树的时候,mount 默认选项为 relatime。设置该选项后,不尽要求访问文件内容,而且 mtime 或者 ctime 比 之前的 atime 要旧或者之前的 atime 要比访问的日期和时间旧至少一天(也就是说上一次访问是在一天之前)时,才会更新 atime。
    这是为了性能考虑。假设 mount 选项为 atime(也就是过去的默认选项),那么每用 read 读一次文件内容到内核缓冲区中时,都会需要写文件(就是更新这个文件的 inode 中的 atime 信息),这大大降低了 I/O 性能。
  • 最后一个字段是文件的文件名。对于符号链接,会有个 -> 符号,指向它所链接的文件。

对该目录下的所有文件(all)按行显示:
ls -la

对该目录下的所有非隐藏文件按行显示,除了显示一般信息外,还会在最开始显示 inode 编号:
ls -li

对该目录下的所有非隐藏文件按行显示,在文件大小处添加单位:
ls -lh

对该目录下的所有非隐藏文件按行显示,除了显示一般信息外,还会在最开始显示该文件所占数据块个数:
ls -ls

对该目录下的所有非隐藏文件按行显示,且按文件的大小顺序依次显示(默认从大到小):
ls -lS

注意:是大写的 S。如果要按从小到大的顺序,则为:ls -lSr

对该目录下的所有非隐藏文件按行显示,且按文件内容最后一次修改的时间依次显示(默认从最近到最久):
ls –lt

注意:-t 参数默认是显示的文件内容最后一次修改的日期和时间。另外,如果要按从最久到最近的顺序显示,则为:ls -ltr

对该目录下的所有非隐藏文件按行显示,且按文件的最后一次状态修改(change status)时间依次显示(默认从最近到最久):
ls -ltc

注意:如果要按从最久到最近的顺序显示,则为:ls -ltcr

对该目录下的所有非隐藏文件按行显示,且按文件的最后一次访问(use)时间依次显示(默认从最近到最久):
ls -ltu

注意:如果要按从最久到最近的顺序显示,则为:ls -ltur

递归地显示该目录下的所有非隐藏文件以及其所有子孙目录的所有非隐藏文件的相应信息:
ls -lR

ls 并没有直接提供对某个目录文件递归求和得到的总大小的功能。若要实现这个功能,则需要联合其他命令共同进行。比如:
ls -lR | grep -v '^d' | awk '{total += $5} END {print "Total:", total}'

另外,要将 ls 命令和 du 命令区别开来,详见 du 命令。

18 创建目录和普通文件

创建一个空目录,默认权限为 755:
mkdir dirname

递归地创建空目录:
mkdir -p test/{dir1/{dir2,dir3},dir4}
对应的目录树为:

1
2
3
4
5
test
├── dir1
│   ├── dir2
│   └── dir3
└── dir4

创建文件可用 touch 命令,如下:
touch filename

19 创建有名管道

mkfifo pipename

20 更改最后一次访问的日期和时间与最后一次修改文件内容的日期时间

更改文件的最后一次访问日期和时间与最后一次修改文件内容的日期和时间为当前日期和时间:
touch filename

更改文件的最后一次访问(access)日期和时间为当前的日期和时间:
touch -a filename

更改文件的最后一次修改(modification)文件内容的日期和时间为某个日期和时间:
touch -mt 201504210800 filename

注意:-t 参数制定日期和时间。

另外,只要用到 touch 命令,最后一次修改文件状态的日期和时间都会被置为当前的日期和时间,因为 touch 命令总会修改 atime 或者 mtime,这就相当于 inode 节点内部信息发生了变化,因此 ctime 也会跟着发生变化。

21 更改或设置文件权限

首先介绍下文件的权限。一般有三种权限,分别是 r, w 以及 x。另外,还有两种特殊权限,分别是 st

对于 /etc/passwd 文件,它的文件权限及其所属用户是:
-rw-r--r-- root
对于 /etc/shadow 文件,它的文件权限及其所属用户是:
-rw-r----- root
对于普通用户是不可以修改它们的。不过,我们知道,可以通过 passwd 命令修改用户密码,而修改密码的实质就是修改这两个文件。那么 passwd 这个命令是怎么做到的呢?

可以看看 /usr/bin/passwd 的文件权限及其所属用户:
-rwsr-xr-x root
发现二进制文件的所属用户对这个文件的权限的第三个字段是 s。事实上,s (SUID) 权限的意思是,由于它的所属用户是 root,因此在执行这个二进制文件时会临时获取 root 的权限。进一步地,当它试图去修改 /etc/passwd 以及 /etc/shadow 这两个文件时,由于获得了 root 权限,因此就可以成功修改它们了。(就好比 sudo)。

注意:要对一个文件的拥有者加上 s 权限,前提必须要保证这个文件拥有者之前就已经获得了 x 权限。否则,即使用 chmod 命令为这个用户添加了 s 权限,也并没有真正地添加上。通过 ls -l 命令可以看到,相应字段为 S,而非 s

对于文件所属用户组,也可同样对其设置 s (SGID) 权限。当一个文件所属用户组拥有了 s 权限后,如果用户组是 root,那么在执行这个文件时,也会临时获取用户组 root 的权限。

我们知道,/temp 的文件权限及其所属用户和所属用户组是:
drwxrwxrwt root root
发现该目录文件的其他用户对这个文件的权限的第三个字段是 t。由于所有用户都可以对这个目录进行读和写,因此可能会出现这么一种状况。如果用户 A 在该目录下创建了一个文件,用户 B 将该文件删除了,这种情况就会引发很多问题,是不能允许的。

t (Sticky Bit) 的设置就是为了避免这个问题。如果一个目录文件设置了 t 权限,那么这个目录里的文件 只能被该文件所有者,这个目录的所有者及 root 删除

注意:Sticky Bit 只对目录文件有效果,对其他文件没效果。另外,只有当这个目录文件的拥有者,所属用户组之外的其他用户对这个文件具有 x 权限时,才能正常地为这个目录文件添加 t 属性,否则即使添加了,只会显示出 T

文件的权限更改或设置有两种方式:

  1. 通过一个八进制数进行修改。
    这里假设更改权限为 0755:
    chmod 0755 filename
    其中,这个八进制数的最高位代表特殊权限,后面三位分别代表文件所有者,文件所属组,其他用户对这个文件的权限。事实上可以把后面三位转换成一个二进制数,每个八进制位转换成的 3 位二进制数中,分别表示 r w x 权限(1 代表有,0 代表没有)。

    注意:特殊权限位对应的二进制数中,最高位代表 SUID,接下来的这位代表 SGID,最低位代表 Sticky Bit。根据上面的分析介绍可知,它们是设置在文件所有者,文件所属组,其他用户对这个文件的 x 权限基础上的。特殊权限位如果为 3(110),则表示文件所有者对这个文件具有 s 权限,用户所属组对这个文件也具有 s 权限。

  2. chmod ug+r+w-x,o=r filename
    其中,u 代表这个文件的拥有者,g 代表这个文件的拥有者所在组的其他用户,o 代表不在这个文件的拥有者所在组的其他用户。然后通过 +- 来添加或撤销相应用户对这个文件的权限,或者直接用 = 来设置相应用户对这个文件的权限。

另外,可以通过 -R 参数,来递归地修改一个目录下的所有文件(对于任意一个子目录,递归地修改它里面的所有文件)。

22 修改和查看文件的隐藏属性

可以通过 +, -, = 增加删除或设置文件的隐藏属性。

修改文件的隐藏属性(+a 表示该文件只能以 Append 方式打开):
sudo chattr +a filename
此时,就不能用 vim 等应用程序编辑文件了,不过可以通过重定向功能在尾部写入。

修改文件的隐藏属性(+i 表示该文件不能被修改,也不能被删除)
sudo chattr +i filename

查看文件的隐藏属性:
lsattr filename

23 更改文件拥有者与文件所属用户组

更改 filename 的拥有者为 uername(username 一定要存在于 /etc/passwd 之中):
chown username filename

更改文件所有者与文件所属用户组(username 一定要存在于 /etc/passwd 之中,groupname 一定要存在于 /etc/group 之中。不要求 username 一定要属于 groupname):
chown username:groupname filename

如果仅仅是更改文件所属用户组(groupname 一定要存在于 /etc/group 之中):
chgrp groupname filename

还可以加上 -R 参数,表示递归地修改一个目录下的所有文件的拥有者以及文件所属用户组。

24 查看文本文件内容

cat (concatenate,连续) 将多个文件打印到屏幕上(先打印 file1,然后打印 file 2),且显示行号:
cat -n file1 file2

注意:cat 的实质是将一个或多个文件作为输入,然后输出到标准输出中。如果没有指定输入文件,默认从标准输入里输入。cat 还有如下使用方式:

从标准输入里输入内容并写入 file 中:
cat > file

从标准输入里输入内容并写入到 file 中(以 EOF 结束输入):
cat > file <<EOF

如果文件行数较大,那么用 cat 的话,需要鼠标滚动查看,会很不方便。可以用 more
more file1 file2

虽然 more 中也提供了很多操作,但是仅能向前移动,不能向后移动,不太灵活。一般常用的是 less
less file1 file2

  • 加上 -N 带行号显示。
  • 可以通过 f 向下翻页,b 向上翻页。
  • /模式字符串 向下查询,?模式字符串 向上查询。n 重复前一个查询,N 反向重复前一个查询。
  • 如果有多个文件,则可以通过 :n 查看下一个文件,通过 :p 查看上一个文件。
  • -i 忽略大小写,并用小写字母进行查询(如果搜索字符串中存在大写字母,则该参数失效);-I 忽略大小写(无论搜索字符串中是否有大写字母,该参数都有效)。
  • q 离开 less 这个程序。

25 查看文件头部内容和尾部内容

查看 filename 的前 10 行:
head -n 行数 filename

查看 filename 的最后 10 行:
tail -n 行数 filename

对于 tail 命令,还提供了 -f 参数,当打开的文件尾部更新时,也会将更新的内容打印出来。例如:
tail -fn 行数 filename
如果直接从尾部开始打印并更新,则直接使用:
tail -f filename

26 查看二进制文件

查看二进制文件,用十进制数显示:
od -t d filename

查看二进制文件,用八进制数显示:
od -t o filename

查看二进制文件,用十六进制显示:
od -t x filename

查看二进制文件,用 ASCII 字符显示:
od -t c filename

27 显示行号

虽然 cat 命令提供了显示行号的选项,但是功能有限。nl 提供了丰富的显示行号的功能。

对空行也显示行号(nl 默认不对空行显示行号):
nl -ba filename

行号左对齐,空格不用零填充:
nl -nln filename

行号右对齐,空格不用零填充:
nl -nrn filename

行号右对齐,空个用零填充:
nl -nrz filename

指定行号位数为 3:
nl -w 3 filename

28 比较两个文件

按行比较两个文件(按照合并格式,会打印出两个文件的上下文,而且会合并两个上下文相似的部分),一般用作比较两个文本文件:
diff -u file1 file2

注意:file1 表示改动前的文件,file2 表示改动后的文件。diff 一般有三种形式。第一种是普通模式,不加任何参数;第二种是上下文格式,参数为 -c ,第三种是合并格式,参数为 -u。对于版本控制系统 Git,里面的 diff 操作就是用的合并格式。
详见:读懂diff

另外,diff 命令常用的还有两个参数:
diff -urN dir1 dir2
其中,-r 表示若是目录文件,则对于 dir1 中的各个文件,递归地将其与 dir2 中的各个文件进行比较,不过只比较同名文件。-N 表示,对于 dir1 中的文件 file,如果 dir2 中不存在与 file 同名的文件,则视为空文件,此时 file 与这个空文件进行比较。

按字节比较两个文件:
cmp file1 file2

29 打补丁

首先使用 diff 命令生成补丁文件:
diff -urN file1 file2 >file.patch

file.patch 中的内容如下:

1
2
3
4
5
6
7
8
diff -rN old/haha.txt new/haha.txt
1,2c1,3
< hello world
< world hello
---
> hello nju
> hello world
> nju world

然后将其对 file2 打补丁:
patch file2 file.patch
该命令会忽视 file.patch 中的路径信息(对于上例来说,就是 old/caca.txt)。

一般情况下,会用如下命令:
patch -p0 <file.patch
此时,会考虑路径信息。-p0 表示从当前目录开始搜索 old 目录,然后在 old 目录中搜索 haha.txt 文件,然后再打补丁。-p1 表示忽略 old 目录,直接从当前目录开始搜索 haha.txt 文件。-pn 类似。

对于一个文件,如果想恢复至打补丁之前的状态,则用如下命令:
patch -R file2 file.patch
或者
patch -R -p0 <file.patch

30 排序与去重

对文件或标准输入的每行按从小到大排序并打印到屏幕(默认忽略前面的空格,从首个非空格字符开始比较):
sort file

按从大到小排序:
sort -r file

默认是按字符的 ascii 值排序的,不过对于数字型字符串,还可以按数值大小进行排序:
sort -n file

默认是根据第一个域(只有一个域)的第一个字符的 ascii 值进行排序,还可以指定某个域的其他位置的字符的 ascii 值进行排序:
sort -k 1.2 file
表示指定第一个域的第二个字符进行排序。

还可以根据某个特定的字符将原字符串划分成多个域,然后指定某个域的某个位置的字符的 ascii 值进行排序:
sort -t ':' -k 3.1 file
表示将每行的字符串以 : 符进行切分,然后以第三个域的第一个字符进行排序。

还可以忽略重复的行,使得重复的行仅出现一次:
sort -u file
当然,对于排序好了的行,还可以用 uniq 命令进行去重。

31 统计文件信息

统计文件行数:
wc –l filename

统计文件字数:
wc –w filename

统计文件字节个数:
wc -c filename

统计文件字符个数:
wc -m filename

32 查看文件类型

打印出文件的类型:
file filename

33 查看系统分区的详细信息

fdisk -l

34 查看某个系统分区的所有详细信息

查看 /dev/sda8 分区的所有详细信息:
dumpe2fs /dev/sda8
其中有逻辑扇区和物理扇区的大小,还有一次 I/O 传输数据的大小。

注意:Sector 分为 logical sector size 和 physical logical size,一般情况下,后者是前者的整数倍。现在硬盘的物理扇区不像以前那样是 512B 了,而一般是 1024B。之所以有逻辑扇区(一般大小为 512B)的出现,是为了兼容一些老的文件系统,它们所认为的扇区大小为 512B。

物理块和逻辑块的大小是文件系统规定的。物理块是相对于磁盘分区来说的,逻辑块是相对于文件来说的。一个文件所占所有物理块不一定有连续的地址,但是一个文件的逻辑块的地址是连续的,从 0 开始编号(类似于一个可执行程序的物理地址空间和逻辑地址空间)。通常情况下,一个物理块大小是逻辑扇区大小的整数倍,一个逻辑块大小是物理块大小的 2^n 倍。逻辑块号到物理块号的映射存储在该文件的 inode节点 中。

I/O block size 是指一次 I/O 所要传输数据的大小。通常情况下,它等于一个逻辑块的大小。

仅查看 /dev/sda8 分区的超级块的信息:
dumpe2fs -h /dev/sda8

35 查看文件的状态以及文件所在系统分区的状态

查看文件的状态:
stat filename
其中,Size 表示该文件大小(单位为 B),Blocks 表示该文件占用的物理块个数,IO Block 表示一次 I/O 传输数据的大小,一般情况下等于一个逻辑块的大小。

一个文件无论多大,至少有一个逻辑块,假设为 4096B。而一个物理块的大小一般为一个逻辑扇区的大小,即 512B。因此,一个文件无论多大,至少占有 8 个物理块。

查看文件所在系统分区的状态:
stat -f filename

36 查看文件系统的空间占用情况

查看所有系统分区上的文件系统的空间占用以及使用情况(显示数据块个数信息):
df

查看所有系统分区上的文件系统的空间占用以及使用情况(显示分区大小信息,单位为 B):
df -h

查看某个文件所在文件系统的空间占用以及使用情况(显示分区大小信息,单位为 B):
df -h filename

查看所有系统分区上的文件系统的空间占用以及使用情况(显示 inode 节点个数信息):
df -i

查看所有系统分区上的文件系统的类型:
df -T

37 查看文件的空间占用情况

文件的大小与文件所占空间的大小是不同的。假设物理快的大小为 1024 B,一个文件的大小为 1025 B,那么这个文件所占空间的大小为 2048 B(两个物理快)。

du [参数] [目录路径或文件路径或 wildcards]

如果不加路径参数,则默认为当前目录所在路径。

查看当前目录的所有子孙目录文件各自空间占用情况(递归地计算每个目录文件所占空间的总大小)以及当前目录文件的空间占用情况(递归地计算当前目录文件所占空间的总大小)(单位为 B):
du -h

直接查看当前目录文件的空间占用情况(单位为 B,相当于是只计算但并不打印出当前目录文件的所有子孙目录的空间占用情况):
du -sh

查看当前目录下各个子目录(不包括其子孙目录)的空间占用情况(单位为 B):
find . -type d -depth 1 | xargs -I {} du -sh {}

查看当前目录下所有命名以 . 开头的普通文件或目录(不包括其子孙目录)的空间占用情况(单位为 B):
du -sh .[!.]*

[!.] 表示不包含 . 的字符,[!.]* 表示任意多个这样的字符。

查看当前目录下某个文件的空间占用情况(单位为 B):
du –h filename
或者
du -lsth filename

38 文件系统以及磁盘分区的挂载与卸载

显示所有文件系统以及磁盘分区的挂载信息:
sudo mount -l

将文件系统或磁盘分区挂载到 dirname 下的 temp 空目录中:
sudo mount 文件系统或磁盘分区 dirname/temp

卸载:
sudo umount 文件系统或磁盘分区
或者
sudo umount dirname/temp

通常可以用这个命令来挂载镜像文件到 dirname 下的 temp 空目录中:
sudo mount -o loop 镜像文件 dirname/temp

还可以用它来挂载 Windows 上的共享文件到 dirname 下的 temp 空目录中:
sudo mount -o username=xxx,password=xxx, //192.168.0.101/共享文件夹 dirname/temp

详情见:Linux下挂载Windows共享目录

39 磁盘格式化(创建文件系统)

将 /dev/sdb 格式化为 exfat 格式(卷名字为 Hello):
sudo mkfs.exfat -n Hello /dev/sdb

将 /dev/sdb 格式化为 fat 格式(卷名字为 Hello):
sudo mkfs.fat -n Hello /dev/sdb

注意:每种格式都有对应的命令。

40 重定向

重定向输入 <:
./main < filename
表示在执行 main 的时候,以 filename 中的东西作为标准输入。

重定向输出 >(指定的目标文件会首先被截断):
cat filename2 filename3 > filename1
表示首先读取 filename2 并写入文件 filename1 中,然后再读取 filename3 并写入 filename1 中。

或者:
ls > a.txt
表示将 ls 的输出内容写入到 a.txt 中。

<<(以某个字符串作为结束标记进行标准输入):
cat > filename <<EOF
表示从标准输入里输入内容并写入到 filename 中(以 EOF 结束输入)。

重定向 >>(追加):
cat filename2 filename3 >> filename1
filename1 不会被清空,从尾部开始写入。

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null
./main > /dev/null

41 归档与压缩

压缩是针对某一个文件进行的,使其占用空间变小。而归档是指将多个文件或目录放到一个文件之中。

归档多个文件或目录(c 表示创建):
tar -cf file.tar filename1 dirname1

释放归档文件(x 表示释放):
tar -xf file.tar

通过 gzip 的支持对每个文件进行压缩,然后再进行归档(z 表示 gzip):
tar -czf file.tar.gz filename1 dirname1

通过 gzip 的支持对每个压缩文件进行解压缩,并释放:
tar -xzf file.tar.gz

通过 bzip2 的支持对每个文件进行压缩,然后再进行归档(j 表示 bzip2):
tar -cjf file.tar.bz2 filename1 dirname1

通过 bzip 2 的支持对每个压缩文件进行解压缩,并释放:
tar -xjf file.tar.bz2

注意:默认情况下,都是归档或释放到当前目录的。如果想释放到指定目录中(必须存在),则可以用 -C 参数指定:
tar -xzf file.tar.gz -C dirname

另外,对于压缩和归档,如果压缩或归档文件名指定为 -,表示将该文件中的内容传递给标准输出;对于解压或释放,如果压缩或归档文件名指定为 -,则表示数据来自于标准输入。

42 作业在前台和后台之间的切换

  • &
    这个用在一个命令的最后,可以把这个命令放到后台执行。
  • ctrl + z
    可以将一个正在前台执行的作业放到后台,并且暂停。
  • jobs
    查看所有作业的作业号和状态。
    jobs -l
    列出所有作业的所有信息,包括进程号。
    jobs -r
    仅列出正在后台运行的作业。
    jobs -s
    仅列出在后台暂停的作业。
  • fg %jobnum
    将后台中的作业调至前台运行。jobnum 是通过 jobs 命令查到的后台正在执行的命令的序号(是中括号中的数字,不是后面的 pid)。
  • bg %jobnum
    将一个暂停的作业放到后台继续执行。%jobnum 同上。
  • kill -9 pid
    这个命令一般与 ps 连用,先用 ps 查看需要杀死的进程的 pid,然后用该命令强制杀死这个进程(9 号信号为强制退出信号)。

43 ctr + c, ctr + d 以及 ctr + s 和 ctr + q

  • ctrl + c
    表示终止程序或者命令的执行。
  • ctrl + d
    表示从键盘输入 EOF。这在终端的文字界面里经常会用到。
  • ctr + s
    表示暂停打印到屏幕。
  • ctr + q
    恢复打印到屏幕。

44 显示进程信息

显示所有进程:
ps –ef
或者
ps -lA
或者
ps aux

只显示与 shell 有关的进程(也即是在 shell 上通过执行命令或可执行程序创建的进程):
ps -l

45 打印环境变量

查询所有环境变量:
env

打印 HOME 的环境变量:
echo $HOME

46 which

查看命令的路径:
which 命令

注意:沿着 $PATH 搜索这个命令,直到被找到为止。
对于 shell 内置的命令,是无法通过这个命令得到路径的,比如 cd 等。

47 tab

  • 如果在打入一个命令时,按一下 tab,可以用来自动补全命令。如果有多个,会列举出所有以打入的命令部分开头的所有命令。
  • 如果是在打入路径信息,那么按一下 tab 会列出该路径下所有的目录和文件。

48 清理屏幕

clear

49 查看系统版本以及系统信息和 CPU 信息

查看系统版本:
cat /etc/issue
事实上,其中的内容是用户登录时打印到屏幕上的系统信息。

查看系统信息:
uname -a

查看 CPU 信息:
cat /proc/cpuinfo

50 查看登录到主机的用户

who
该命令会打印出所有登录到当前主机的用户。比如说除了自己之外,可能还有其他用户通过 ssh 或者其他方式登录到这台主机上,用这个命令的话,会把所有登录用户都打印出来。

51 查看有效用户

whoami
该命令会查看有效用户,也即执行这条命令的用户的名字。

52 文件转码

查看系统支持的编码:
iconv -l

将一个文件由 gb2312 转换成 utf-8(f 代表 from,t 代表 to):
iconv -f gb2312 -t utf-8

将一个文件由 gb2312 转换成 utf-8,并另存到文件 newfile 中:
inconv -f gb2312 -t utf-8 -o newfile

53 查看与设置系统字符编码

查看系统当前的字符编码:
locale

设置系统当前的字符编码:
打开 /etc/default/locale 文件,然后更改 LANG 为想修改的字符编码。

54 查看并调整 Ext 文件系统中的可调参数

查看 Ext 文件系统的可调参数(包括逻辑块大小等参数):
sudo tune2fs -l /dev/sda6

55 查看并调整区块设备的参数

通过调用 ioctl 函数来查看或调整设备的参数。

查看该设备的逻辑块大小(block size 或者 I/O block size):
sudo blockdev --getbsz /dev/sda6

56 查看与设置限制

查看所有限制及其额度:
ulimit -a

上面的这个命令可以列出不同的限制,额度,还有相应的参数。可以通过这些参数来设置额度,比如:
ulimit -c 1024
这个命令是调整 core file 的大小为 1024 个 block size 大小。当某些进程发生错误时,系统可能会将该进程在内存中的信息写成文件,这个文件称为 core file。gdb 中就是用这个文件进行 debug。

57 查看系统中的 shell 与更换登录 shell

查看系统中的 shell:
cat /etc/shells

更换 登录shell(假设更换为 zsh):
chsh -s /bin/zsh
然后重启。

58 命令行的编辑

查看命令历史记录:
history

上一条命令记录:
上方向键

下一条命令记录:
下方向键

命令自动补全:
tab键

删除光标到行尾的字符:
ctr + k

删除光标之前的一个单词:
ctr + w

删除删除光标前面所有字符 (bash) 或整行 (zsh):
ctr + u

撤销上一次的删除操作:
ctr + y

将光标移动到行首:
ctr + a

将光标移动到行尾:
ctr + e

59 周期性地执行命令

每隔 1 秒执行一次 command,并以高亮显示不同之处:
watch -n 1 -d "ls -la"

注意:由于命令是传给 watch 的,因此需要在命令两端加上双引号,使得 shell 在处理的时候将其中的命令当作普通字符串。

60 域名解析

采用 dig 命令进行域名解析。除此之外,还可以用 nslookup 命令,它是一种交互式的命令,在操作中需要手动输入一些参数,较为不便。

关于域名及其 DNS 的了解详见:DNS原理入门

dig 命令的基本格式为:
dig @域名服务器 域名 记录类型
例如:
dig baidu.com

  • 域名服务器 为一个 DNS 服务器的 IP 地址,表示通过这台 DNS 服务器查询域名的相应记录。如果不加 @域名服务器,那么就从 /etc/resolv.conf 中的 nameserver 中读取对应的 IP 地址,作为默认的域名服务器的 IP 地址;
  • 域名 即为所要查询的域名。如果不指定,则默认为查询根域名服务器的相应记录;
  • 记录类型 一般有 A,AAAA,NS,CNAME。如果不指定,则默认为查询 A 记录。

该命令会采用递归地方式进行域名解析。

还有一种是采用迭代地方式进行域名解析:
dig +trace @域名服务器 域名 记录类型

dig 命令的详细介绍详见上面的链接以及 域名解析之dig,host,nslookup命令

61 系统调用跟踪

执行应用程序并跟踪所需要的系统调用:
strace 应用程序

62 查看日期

查看当前日期:
date

按给定格式打印:
date +%Y-%m-%d-%H-%M-%S

63 update-alternatives 命令

对于某个命令存在多个版本时,或者某个类型的命令存在多种选择时,可以用 update-alternatives 进行选择具体的命令。

安装命令到某个组中:
sudo update-alternatives --install link name path priority --slave link name path

其中,

  • link 为命令的一个符号链接(链接到 /etc/alternatives/ 中的某个组名);
  • name 为安装过程中存放到 /etc/alternatives/ 的组名(链接到 path 所指命令);
  • path 为所安装的命令的路径;
  • priority 为该命令的的优先级(自动模式下通过该值选择优先级最高的版本)。
  • --slave 前面的作为命令选择的主要部分,后面的作为从属部分。该参数是可选项,可以不指定从属部分。

当选择某个命令时,也会自动选择其从属部分对应的命令(若指定了)。

例如将特定版本的 vim 命令安装到 editor 组中,并将其对应的 man 手册作为从属部分安装到 /usr/share/man/man1/editor.1.gz 中:
sudo update-alternatives --install /usr/bin/editor editor /home/linuxbrew/.linuxbrew/bin/vim 40 --slave /usr/share/man/man1/editor.1.gz editor.1.gz /home/linuxbrew/.linuxbrew/share/man/man1/vim.1

交互式选择某个组中的命令:
sudo update-alternatives --config name

针对上面的例子,当选择指定的 vim 命令后,实质上会修改 /etc/alternatives 中的 editor 符号链接,使其指向该 vim 命令。可以通过运行:
editor
命令和
man editor
命令进行查看更改后的效果。

非交互式选择某个组中的命令:
sudo update-alternatives --set name path

查看某个组的所有命令:
sudo update-alternatives --display name

删除某个组的命令及其从属部分:
sudo update-alternatives --remove name path

删除某个组的所有命令及其从属部分:
sudo update-alternatives --remove-all name

64 使用 timeout 控制命令执行的最长时间

一般用法:
timeout 时间 command
如果超出指定时间后命令仍在执行,则默认会发送 SIGTERM 信号给 command 对应的子进程。

其中,时间是一个浮点数后面跟上一个后缀。后缀有:

  • s,代表秒;
  • m,代表分;
  • h,代表小时;
  • d,代表天。

此外,也可以用 -s 参数发送其他信号:
timeout -s SIGKILL 时间 command

65 多主机间传输文件

使用 scp 或者 nc 命令。

还可以使用 Python:

在远程主机上执行:
python -m SimpleHTTPServer 9999
或者
python3 -m http.server 9999
该命令,会以当前目录为 web 根目录,然后启动一个 HTTP Server。

然后在另一台主机上的浏览器中输入:
远程ip:9999
即可查询下载远程主机上 web 根目录下的所有文件。

66 漂亮地打印 json 字符串

使用 python3 中的 json.tool。例如:
echo '{"json":"obj"}' | python3 -m json.tool

也有一些网站提供此功能,比如:
http://www.json.cn

67 将输出内容以表格的形式显示出来

使用 column 命令可以做到这点:
column -t file

默认情况下,以空白符作为分隔符。也可以通过 -s 参数指定分隔符:
column -t -s 分隔符 file

68 重复执行一个命令,直到它运行成功

主要使用 && 的特点:

1
2
3
4
while true
do
ping -c 1 google.com && break
done ;

69 用 dd 生成指定大小的文件

dd if=/dev/zero of=out.txt bs=1M count=10
这样就会创建出一个 10 MB 的文件,其内容用 0 填充。

70 apt-get 包管理工具

apt-get 是 Ubuntu 上的包管理工具。

  • sudo apt-get update,更新源指定的可用包列表。

    注意:如果因为依赖关系的问题导致更新失败,则可以用如下命令自动修复依赖关系:

    `sudo apt-get -f install`
    -f 表示修复。
    
  • sudo apt-get install package,安装包。
  • sudo apt-get reinstall package,重新安装包。
  • sudo apt-get dist-upgrade,更新系统中的所有包。
  • apt-cache rdepends package,查看该包被哪些包依赖。
  • apt-cache depends package,查看该包依赖了哪些包。
  • apt-cache show package,获取包的相关信息,如说明、大小、版本等。
  • sudo apt-get purge package ,删除包,包括删除配置文件等。
  • sudo apt-get autoremove,自动清除不必要的包。

Reference

  • 鸟哥的Linux私房菜: 基础学习篇