
Ubuntu低频实用命令
最近在工作的时候,总是会遇到这样一个情况,就是在某个特定的场合下,需要用一个具体功能的命令,这个命令之很久之前用过,但是因为最近没怎么用,忘记了命令的格式。于是又不得不去网上搜索,然后找到熟悉的博客,找到丢失的记忆。
久而久之,就觉得很烦,所以决定专门写一个文章,把这些低频而又实用的命令记录下来。
1. 软连接:ln -s
Linux系统及其发行版系统中,使用的文件系统基本都是ext系列的。而ext文件系统中有一个概念,就是链接。链接可以视为文件或者目录的镜像。直观的理解,有所谓的链接(link),我们可以将其视为文件或者目录的别名。
链接分软链接和硬链接两种,常用的是软连接,因为硬链接会导致文件在硬盘中存在多个镜像。
A. 创建软连接
ln命令可以用于创建软连接或者硬链接,其格式为:
ln [参数] [源文件或目录] [目标文件或目录]
创建软连接的格式为:
ln -s [源文件或目录] [目标文件或目录]
例如我现在在当前目录下创建一个指向~/project/data/cifar10的软连接,则命令为:
mkdir datasets
ln -s ~/projects/data/cifar10 ./datasets/cifar10
B. 删除软连接
rm命令可以用于删除文件或者目录,软连接自然也可以。
rm [软链接]
但是需要注意的是,删除软连接的时候,不能加/,例如,现在要删除上面创建的cifar10软连接,那么就要用
rm -r cifar10
注意,不能用:
rm -r cifar10/
因为cifar10是一个软连接,如果我们加了/,就会对其进行转义,从而删除掉~/project/data/cifar10/文件夹下的所有文件,但是cifar10这个链接文件本文会被保存下来。
C. 查看软连接
我们如果要查看软连接所指向的文件,那么直接用ls命令即可。
ls -al ./
ls的-l参数会解析软连接,并且显示出软连接指向的文件。
2. 压缩和解压缩.tar.gz/.tgz
压缩文件能够方便的在不同的计算机之间传输数据,亦或者是使用at、crontab等命令定期的备份数据。
压缩、解压zip格式压缩文件很简单,直接zip、unzip即可,而且参数也不多,非常好记。
但是用于压、解压.tar.gz/.tgz格式压缩文件的tar命令的参数很多,总是记不住,所以干脆就记录下来,方便以后查询
A. 基本参数
| x | extract,解压 |
| c | compress,压缩 |
| z | 压缩/解压的文件是gzip,即后缀是.tar.gz或者.tgz |
| v | verbose,显式压缩(解压)过程中压缩(解压)的文件 |
| f | 解压的文件名(压缩时生成的压缩文件名) |
B. 压缩
压缩直接使用下面的组合
tar -czvf 压缩后生成的文件名 要压缩的文件/文件夹名
此外,需要注意的是,tar在压缩的时候会保存文件夹的结构,因此我们要压缩一个文件夹的时候,最好在该文件夹外进行压缩。
例如我们要压缩一个名为~/file/test/的文件夹时,使用下面的命令
cd ~/file
tar -czvf test.tar.gz test/
这样解压完了之后得到test一整个文件夹
但是如果我们按照下面的方式进行压缩
cd ~/file/test
tar -czvf ./*
那么解压的时候就会得到很多文件
C. 解压
解压使用下面的组合
tar -xzvf 要解压的文件名
3. 非交互式SSH连接:sshpass
在开发的过程中,很多时候我们都需要干一些重复的事情。因此如果有一些任务在未来一段时间我们重复会干的话,那么我们就可以把这一系列任务写成一个Shell脚本,以后直接调用即可。
而很多时候,我们在本机上完成好了开发之后,需要上传到内网的机器中进行测试。手动的用tar打包完了之后再用scp命令上传到内网服务器中是真的很麻烦。因此我们就想能不能把代码的打包以及上传写成一个脚本。
可是这样干优惠存在一个问题,就是scp或者ssh这样涉及到链接远程服务器的命令都是交互式的,换而言之需要我们手动输入密码,这样就为我们在Shell中集成工作流造成了很大的不便。
因此,我们就在想能不能把密码当成参数传给scp或者ssh,很可惜,这样不行。所以这个时候就有sshpass这个工具来帮助我们了。
A. -p 指定密码
使用-p参数直接指定ssh和scp登录时的密码
# 免密码登录
sshpass -p password ssh username@host
# 远程执行命令
sshpass -p password ssh username@host <cmd>
# 通过scp上传文件
sshpass -p password scp local_file root@host:remote_file
# 通过scp下载文件
sshpass -p password scp root@host:remote_file local_file
所以组合在一起,我们首先在本地使用tar打包,然后使用scp把压缩好的文件上传到远程服务器上去,接下来使用ssh命令远程执行解压、编译、测试的命令。
类似的,如果想在远程执行多个命令,我们可以先用scp把写好的shell脚本上传到远程服务器上去,然后再使用ssh命令远程执行shell脚本。
B. -o 忽略RAS Key检查
在第一次链接到远程服务器的时候,第一次认证时,一般会有RSA Key验证的提示:
The authenticity of host ’10.x.x.x (10.x.x.x)' can't be established.
RSA key fingerprint is a4:eb:8c:7d:2a:ef:d6:1c:a3:0c:e8:e5:00:d2:eb:60.
Are you sure you want to continue connecting (yes/no)?
这个时候可以指定-o参数来忽略RSA Key的验证
sshpass -p "$SSH_PASSWD" ssh root@"$host" -o StrictHostKeyChecking=no "$@" 2>/dev/null
C. -f 从文件中读取密码
使用-f参数从文件中读取密码
echo "password" > userpasswd
sshpass -f userpasswd ssh username@x.x.x.x
当然可以配合gpg来加密密码,而使用时候把解密后的密码传给sshpass,最后再删掉即可。
gpg -d -q .sshpassword.gpg > fifo; sshpass -f fifo ssh; rm fifo
D. -e 从环境变量中读取密码
使用-e参数从环境变量中读取密码
export SSHPASS="password"
sshpass -e ssh username@x.x.x.x
4. 测试程序用时:time
很多时候,我们需要测试一个程序、命令运行所花费的时间,为此,我们可以使用Linux中的time命令
A. 基本使用
time 需要计算时间的程序
例如我们下面测试ls的用时
time ls
其中:
real时间是指挂钟时间,也就是命令开始执行到结束的时间。这个短时间包括其他进程所占用的时间片,和进程被阻塞时所花费的时间。user时间是指进程花费在用户模式中的CPU时间,这是唯一真正用于执行进程所花费的时间,其他进程和花费阻塞状态中的时间没有计算在内。sys时间是指花费在内核模式中的CPU时间,代表在内核中执系统调用所花费的时间,这也是真正由进程使用的CPU时间。

但是需要注意的是,这里使用的time是shell这个程序的内置命令,而非在PATH中的可执行程序/usr/bin/time,因此,直接使用time的功能有限。
shell搜索命令的次序依次为:
- 检测命令是否为
alias的命令 - 对命令进行参数扩展
- 检测命令是否是
shell脚本中定义的函数functions - 检测命令是否是
shell的内建命令BUILTIN commands - 检测
HASH table - 搜索
PATH中是否存在同名程序
因此,由于shell的BUILTIN commands就有time,所以如果直接使用的话,用的就是BUILTIN commands而非PATH中的可执行的time二进制文件
为此,可以在time命令前加上\表示强制使用PATH中的命令,则此时
\time ls

B. -f 格式化输出
使用-f选项格式化时间输出:
\time -f "time: %U" ls

-f选项后的参数:
| 参数 | 描述 |
|---|---|
%E |
real时间,显示格式为[小时:]分钟:秒 |
%U |
user时间。 |
%S |
sys时间。 |
%C |
进行计时的命令名称和命令行参数。 |
%D |
进程非共享数据区域,以KB为单位。 |
%x |
命令退出状态。 |
%k |
进程接收到的信号数量。 |
%w |
进程被交换出主存的次数。 |
%Z |
系统的页面大小,这是一个系统常量,不用系统中常量值也不同。 |
%P |
进程所获取的CPU时间百分百,这个值等于 user+system 时间除以总共的运行时间。 |
%K |
进程的平均总内存使用量(data+stack+text),单位是 KB。 |
%w |
进程放弃CPU的次数,即主动进行上下文切换的次数,例如等待I/O操作完成。 |
%c |
进程被抢占CPU的次数,即被迫进行上下文切换的次数(由于时间片到期)。 |
C. -o 写入到文件中
使用-o选项将执行时间写入到文件中:
\time -o outfile.txt ls
cat outfile.txt

5. 标准输入作为参数:xargs
xargs是 Linux 系统的一个很有用的命令,但是常常被忽视,很多人不了解它的用法。
A. 介绍
Linux 命令都带有参数,有些命令可以接受标准输入(Stdin)作为参数,例如grep命令:
cat /etc/passwd | grep root
上面的代码使用了管道命令(|)。管道命令的作用,是将左侧命令(cat /etc/passwd)的标准输出转换为标准输入,提供给右侧命令(grep root)作为参数。
因为grep命令可以接受标准输入作为参数,所以上面的代码等同于下面的代码。
grep root /etc/passwd
然而,能够接收标准输入作为参数的命令只是少数,大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数。例如,echo命令就不接受管道传参。
echo "hello world" | echo
上面的代码不会有输出。因为管道右侧的echo不接受管道传来的标准输入作为参数。因此,这就极大地限制了我们使用管道符来连接多个命令,从而实现整个工作流。
因此,如果我们有命令,能够让所有的命令接收标准输入作为参数,那么就可以极大地提高我们的工作效率,而xargs就是这个命令。
B. 基本使用
xargs命令的基本用法如下
xargs [options] [command]
其中:
options是命令行参数command是将要传入参数的命令
如果没有指定command的话,那么默认将运行echo。例如
ps aux | grep grep | xargs

C. -p 确认运行
有的时候可能会运行诸如rm等高危命令,因此xargs提供了-p参数来向用户确认是否运行命令
ps aux | grep grep | awk '{print $2}' | xargs -p kill -9
此时输入y/Y来确认运行,其他的字符都视为不运行。

D. -t 输出执行的命令
-p会阻塞程序,直到用户输入。有的时候我们只希望需要输出一下将要执行的命令,而不阻塞程序运行,这个时候就可以使用-t参数。
ps aux | grep grep | awk '{print $2}' | xargs -t kill -9

E. -I 保存输出到变量
有的时候我们希望能够将标准输出的内容传递给多个命令,例如:
echo dirs.txt | xargs .... echo dirs_to_make; mkdir dirs_to_make
这个情况下,解决办法就是我们将前一个命令的输出保存到一个变量中,而后通过取值就可以多次使用前一个命令的输出值。
xargs中通过指定-I参数,来指定变量名
echo "one\ntwo\nthree" > foo.txt
cat foo.txt
cat foo.txt | xargs -I files echo files

但是,如果我们想用多次调用的话,使用;链接是不行的,因为shell会认为;前的是一个命令,即如果我们使用下面的命令来尝试运行多个命令
cat foo.txt | xargs -I files echo files; echo files
那么在shell中,这就成了两个命令
cat foo.txt | xargs -I files echo files
和
echo files
那么这样,第二个命令中的file自然无法被xargs替换,所以运行结果如下

所以如果我们想要使用xargs讲输出传给多个命令的话,就要用下面的调用方法
cat foo.txt | xargs -I files $SHELL -c 'echo files;echo files'

F. -d 指定分隔符
xargs默认上一个命令输出的分隔符是空格和换行,而$PATH的分隔符是:。所以这种时候,可以使用xargs的-d参数来指定分隔符。
注意-d参数在macOS上的xargs不支持,不过可以使用awk的RS和ORS来实现类似的替换效果
echo $PATH | xargs -d ':' -I p bash -c 'echo -e "p"' > searching_path.txt
cat searchin_path.txt
