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