这里的 wildcards
指的是能够被 shell
扩展的符号。
如果在执行的命令中出现这些符号,shell
会对这些进行解析,解析完成后再传入需要执行的命令。
也就是说只要 shell
支持,这些 wildcards
是可以在任意命令中使用的。
常见的 wildcards
有以下几种:
*
:匹配任意数量( 包含0
个 )的字符。**
:递归匹配任意数量( 包含0
个 )的字符。?
:匹配单个任意字符。[]
:匹配出现在中括号中的某个符号。 在中括号中可以使用-
来表示范围,!
(或~
)来表示取反,例如[!0-9]
表示匹配不是数字的字符,[~ab]
表示不是a
也不是b
的字符。{}
:中间内容使用,
分隔,表示多个匹配,例如a{b,c}d
表示匹配abd
或者acd
。 该通配符会将一个字符串转换成多个字符串,例如mv file_{old,new}
会被解析成mv file_old file_new
。 该通配符还可以进行嵌套,例如echo a{b{c,d},e}f
会被解析成echo abcf abdf aef
。 该通配符中如果要表示范围,需要使用..
,例如echo {a..z}
会被解析成echo a b c ... z
。
上面的通配符并不是所有的 shell
都支持的,但是在 bash
中是支持的。例如在 fish shell
中,只有
*
、**
以及 ?
是支持的,其中 *
和 ?
不会匹配 /
,而 **
会匹配 /
,也就是说 **
是
递归匹配。
注意:在正则表达式的语法中,*
表示匹配前面的字符 0 次或者多次,
?
表示匹配前面的字符 0 次或者 1 次,[]
表示匹配中括号中的任意一个字符,
-
表示范围,^
表示取反。
选项 | 说明 |
---|---|
-n |
显示行号 |
-b |
显示非空行的行号 |
-s |
合并多个空行为一个空行 |
-v |
使用 ^ 和 M- 显示不可打印字符,换行和制表符除外 |
-E |
在每行的结尾显示 $ |
-T |
将制表符显示为 ^I |
-A |
等价于 -v -E -T |
-e |
等价于 -v -E |
-t |
等价于 -v -T |
- |
从标准输入读取内容 |
使用 cat
可以直接创建带有内容的文件或者追加内容到文件中,例如 cat > file
会等待输入,
当输入完成后,使用 ^D
(EOF, end of file) 来结束输入。
如果要追加内容到文件中,可以使用 cat >> file
。
-
可以出现在多个文件的任意位置,
例如 cat file1 - file2
表示将标准输入中读取到的内容放置在 file1
和 file2
的内容之间,
而 cat file1 - file2 - file3
表示将标准输入中读取到的内容放置在 file1
和 file2
的内容之间、
file2
和 file3
的内容之间。需要注意的是,此时会要求输入两次,第一次输入完成后,使用 ^D
结束,
然后输入第二次,再次使用 ^D
结束,第一次输入的内容会放置在 file1
和 file2
的内容之间,
第二次输入的内容会放置在 file2
和 file3
的内容之间。
补充:tac
可以将文件内容逆序输出 (优先输出最后一行),tac
的名字来源于 cat
的逆序。
题外话:cat
的名字来源于 concatenate
,即连接的意思,其可以将多个文件的内容拼接在一起。
选项 | 说明 |
---|---|
-r |
递归搜索目录 |
--include "*.py" |
搜索指定文件 |
--exclude "test*" |
排除指定文件 |
--exclude-dir "test*" |
排除指定目录 |
--color=auto,always,never |
何时进行高亮 |
-n |
显示所在文件中的行号 |
-l |
只显示包含匹配项的文件名 |
-L |
只显示不包含任何匹配的文件名 |
-i |
忽略大小写 |
-v |
反向匹配 |
-c |
显示匹配次数 |
-o |
只显示匹配的部分 |
-m |
指定最大匹配的次数 |
-f |
从文件中读取模式。文件中每行一个模式 |
-e |
指定匹配模式 |
-w |
只匹配完整单词 |
-x |
只匹配整行 |
-A 2 |
显示匹配行的后两行 |
-B 2 |
显示匹配行的前两行 |
-C 2 |
显示匹配行的前两行和后两行 |
-E |
使用扩展正则表达式 |
-F |
使用固定字符串。这个选项会将模式中的特殊字符当作普通字符对待 |
-H |
强制显示文件名 |
-h |
强制不显示文件名 |
注意:在 grep
中,完整单词指的是前后均不是字母、数字或者下划线的部分。
注意:-m 1
在有多个文件的时候,每个文件都会显示一个匹配的行,而不是总共只显示一个匹配的行。
题外话:grep
的名字来源于 g/re/p
,其中 g
表示 global
,re
表示 regular expression
,
p
表示 print
,直译即全局正则表达式打印。
选项 | 说明 |
---|---|
-r |
逆序排序 |
-n |
按照数字排序 |
-k |
按照某一列排序 |
-u |
去重 |
-t |
指定分隔符 |
-f |
忽略大小写 |
-h |
人类可读的排序。例如 1K 会被排序到 512 的前面 |
-M |
按照月份排序 |
--files0-form=- |
从标准输入读取以 NUL 作为文件名分隔符的多个文件内容 |
--files0-form=filename |
从某个文件中读取 NUL 作为文件名分隔符的多个文件内容 |
-c |
检查文件是否已经排序 |
注意:-k
可以指定多个列,例如 -k2,2 -k1,1
表示先按照第二列排序,然后再按照第一列排序。
-k
也可以按照某列的部分进行排序,例如 -k2.2,2.3
表示按照第二列的第二个字符到第三个字符进行排序。
-k
还可以指定列的类型,例如 -k2n,2
表示按照第二列的数字进行排序。
-r
选项也可以指定到 -k
选项中,例如 -k2r,2
表示按照第二列逆序排序。
选项 | 说明 |
---|---|
-F |
指定输入的分隔符。 |
-f |
指定 awk 脚本文件。 |
$0
: 所有列。$1
: 第一列。...
$NF
: 最后一列。
例如可以使用 awk '{print $1,$2,$NF}'
打印出每行的第一列、第二列和最后一列。
可以通过 OFS=
(Output Field Separator) 来指定输出的分隔符,例如 awk '{print $1,$2,$NF}' OFS=","
表示使用 ,
作为分隔符。也可以在 BEGIN
模式串中指定 OFS
,例如 awk 'BEGIN {OFS=","} {print $1,$2,$NF}'
。
除了 OFS
以外,还有 FS
用于指定输入文件的分隔符。
除了之前提到的 OFS
, FS
之外,还有一些预定义变量:
NR
: 当前行的行号。NF
: 当前行的列数。RS
:记录分隔符,默认是换行符,也就是每一行作为一条记录。ORS
:输出的记录分隔符,默认是换行符。FILENAME
:当前文件的文件名。FNR
:当前文件的行号,当时用多个文件的时候,NR
记录的是当前的总行号,FNR
记录的是当前文件的行号。
我们可以使用 awk 'NR > 1'
从第二行开始打印,也可以使用 awk 'NF > 0'
打印列数大于 0
的行
(即移除空行)。
如果要打印第一行到第四行,我们可以通过 awk 'NR == 1, NR == 4'
来实现。
我们也可以使用 awk 'NR >= 1 && NR <= 4'
来实现。
BEGIN
和 END
模式串:
BEGIN
: 在处理输入之前执行。END
: 在处理输入之后执行。
例如可以使用
awk 'BEGIN {print "Start"} {print} END {print "End"}'
在处理输入之前和之后打印出 Start
和 End
。
在 awk
中可以使用模式来过滤行,
例如 awk '$1 > 10'
表示只打印第一列大于 10
的行 (当不书写动作时,默认动作是打印整行)。
也可以使用搜索模式,例如 awk '/pattern/'
表示只打印包含 pattern
的行,搜索模式支持正则表达式。
,
也可以和搜索模式一起使用,
例如 awk '/pattern1/,/pattern2/'
表示打印找到的 pattern1
到 pattern2
的行。
~
可以用来表示是否与搜索模式匹配,例如 awk '$1 ~ /pattern/'
表示第一列是否包含 pattern
。
!~
可以用来表示是否不匹配,例如 awk '$1 !~ /pattern/'
表示第一列是否不包含 pattern
。
我们也可以书写 awk
脚本实现更加复杂的功能,例如下面的脚本可以实现统计文件中每个单词出现的次数:
#! /usr/bin/awk -f
BEGIN {
# 设置输入和输出的分隔符
FS=":"
OFS=" "
tot_count = 0
}
{
for (i = 1; i <= NF; i++) {
words[$i]++
tot_count++
}
}
END {
print "Total words:", tot_count
for (word in words) {
print word, words[word]
}
}
注意:由于在 awk '{print}' file
的意思是对某个文件的内容进行处理,
所以要用 awk -f file
来表示将文件作为脚本执行。
awk
中还有一些内置函数,例如 length
函数可以返回字符串的长度,substr
函数可以返回字符串的子串,
我们可以使用下面的命令计算最后一列 (从第二行起) 的数字和:
awk 'NR > 1 { printf "%s",$NF"+" }' OFS="" | awk '{ print substr($0, 1, length($0) - 1) }' | bc
在 awk
中,print
会在输出的字符串后面自动添加换行符,而 printf
可以进行格式化输出,
上面的例子中我们通过 printf
来输出不带换行符的字符串。在 awk
中字符串是可以直接拼接的,
例如 printf "%s", $NF"+"
表示将最后一列的值和 +
拼接在一起。
printf
的格式化方法与 C/C++
中的类似,这里不再进行详细介绍。
当然要实现同样的功能有更简单的命令:
awk 'NR > 1 { sum+=$NF } END { print sum }'
# or
awk 'NR > 1 { print sep $NF; sep="+" }' OFS="" ORS="" | bc
注意:在 awk
中,下标是从 1
开始的,而不是从 0
开始的,且区间是闭区间。
这里再列出一些常用的内置函数:
tolower
:将字符串转换为小写。toupper
:将字符串转换为大写。split
:将字符串按照某个分隔符分割为数组。接收三个参数,第一个参数是要分割的字符串, 第二个参数是数组名,第三个参数是分隔符。在分隔符部分,我们可以传入搜索表达式, 例如split($0, words, /:+/)
表示将当前行按照:
(或者多个连续的:
) 分割为数组。gsub
:全局替换。接收三个参数,第一个参数是查找字符串,第二个参数是替换后的字符串, 第三个参数要替换的文本。 例如gsub(/pattern/, "replace", $0)
表示将当前行中的pattern
替换为replace
。system
:执行系统命令。例如system("ls")
会执行ls
命令并将结果输出到标准输出。
前面介绍到 FS
和 OFS
可以指定输入和输出的分隔符。如果我们想要直接改变分隔符后输出,
我们可能会写出 awk '{print}' FS=':' OFS=' '
这样的命令,试图将 :
改成空格。
但是这样并不能正确工作,
在 awk
中只有当列被修改后 (或者在 print
中打印多个 fields
的时候) 才会使用新的输出分隔符,
所以我们可以通过 awk '($1=$1) || 1' FS=':' OFS=' '
来实现 (这里省略了动作,因此会打印一整行)。
这里的 ($1=$1) || 1
是为了保证能够成功输出原始的空行,因为空行在赋值后返回的是空字符串,而空字符串在
awk
中被当作 false
,所以我们需要通过 || 1
来保证输出。这里的括号是必须的,如果没有括号,
$1=$1 || 1
会被解释为 $1=($1 || 1)
,这样会将 $1
赋值为 1
,而不是保留原来的值。
题外话:awk
的名字来源于三个创始人的名字 Alfred Aho
、Peter Weinberger
和 Brian Kernighan
的首字母。
awk
中支持 POSIX
字符类:
[:alnum:]
:字母和数字。[:alpha:]
:字母。[:blank:]
:空格和制表符。[:cntrl:]
:控制字符。[:digit:]
:数字。[:graph:]
:可打印字符,不包括空格。[:lower:]
:小写字母。[:print:]
:可打印字符,包括空格。[:punct:]
:标点符号。[:space:]
:空白字符。[:upper:]
:大写字母。[:xdigit:]
:十六进制数字。
例如,我们可以使用 awk '/[[:digit:]]/'
来匹配包含数字的行。当然也可以写成 awk '/[0-9]/'
。
选项 | 说明 |
---|---|
-type |
指定文件类型。f 表示普通文件,d 表示目录,l 表示符号链接 |
-readable |
查找当前用户可读文件或目录 |
-writable |
查找当前用户可写文件或目录 |
-executable |
查找当前用户可执行文件或目录 |
-name |
指定文件名。可以使用 wildcads |
-path |
指定路径。可以使用 wildcards |
-iname |
忽略大小写的文件名 |
-ipath |
忽略大小写的路径 |
-empty |
查找空文件或者空目录 |
-perm 644 |
查找权限为 644 的文件或目录 |
-mtime +1 |
修改时间在一天前的文件或目录 |
-atime +1 |
访问时间在一天前的文件或目录 |
-ctime +1 |
创建时间在一天前的文件或目录 |
-mmin +1 |
修改时间在一分钟前的文件或目录 |
-amin +1 |
访问时间在一分钟前的文件或目录 |
-cmin +1 |
创建时间在一分钟前的文件或目录 |
-user |
指定拥有者 |
-group |
指定所属组 |
-delete |
删除查找到的文件或目录 |
-maxdepth |
指定查找的最大深度 |
-mindepth |
指定查找的最小深度 |
-and |
逻辑与 |
-or |
逻辑或 |
-not |
逻辑非 |
-P |
不跟踪符号链接 (默认行为) |
-L |
跟踪符号链接 |
-H |
只跟踪指定的路径或文件的符号链接。例如 -H . 只对 . 目录下的符号链接进行跟踪 |
-print0 |
使用 NUL 作为文件名分隔符 |
-regex |
使用正则表达式匹配文件名 |
-iregex |
使用忽略大小写的正则表达式匹配文件名 |
-samefile |
指定文件的硬链接。例如 find . -samefile file 表示查找和 file 硬链接的文件 |
-links |
指定文件的硬链接数。例如 find . -links 2 表示查找硬链接数为 2 的文件,+ 和 - 可以用来表示大于和小于 |
-type
还可以以下类型有:
b
:块设备文件c
:字符设备文件p
:管道文件s
:套接字文件
注意:使用正则表达式匹配含有某个串的文件名时,需要使用 .*
来表示任意数量的字符,
例如 find . -regex ".*pattern.*"
,而不能直接使用 find . -regex "pattern"
。
注意:如果要使用复杂的逻辑表达式,需要使用 ()
来分组,
例如 find . \( -name "*.txt" -or -name "*.md" \)
表示查找所有 txt
或者 md
文件,
其中的括号需要进行转义,这是因为 Shell
往往会对括号进行特殊处理。
-size
参数有以下几种单位:
b
:块,取决于文件系统,默认是512
字节c
:字节k
:千字节 (1024 字节)M
:兆字节 (1024 千字节)G
:吉字节 (1024 兆字节)
知道了上述单位后,查找某个固定大小的文件只需要指定大小和单位即可,
例如 find . -size 1M
表示查找大小为 1
兆字节的文件。
但是通常我们会查找大于或者小于某个大小的文件,这时候我们可以使用 +
和 -
来表示大于和小于,
例如 find . -size +1M
表示查找大于 1MB
的文件,find . -size -1M
表示查找小于 1MB
的文件。
这两者也可以结合使用,例如 find . -size +1M -size -2M
表示查找大于 1MB
且小于 2MB
的文件。
-exec
可以对查找到的文件执行操作,
例如 find . -name "*.txt" -exec cat {} \;
表示查找当前目录下的所有 txt
文件并将其内容输出到标准输出。
{}
会被替换为查找到的文件名,\;
表示结束,分号需要进行转义,防止被 Shell
解释。
也可以使用 grep
命令过滤查找到的文件,
例如 find . -name "*.txt" -exec grep "pattern" {} \;
表示查找当前目录下的所有 txt
文件并在其中查找 pattern
。
选项 | 说明 |
---|---|
-c |
创建文档 |
-f |
指定文件名 |
-v |
显示详细信息 |
-z |
使用 gzip 压缩或解压 |
-j |
使用 bzip2 压缩或解压 |
-J |
使用 xz 压缩或解压 |
-x |
提取文档 |
-C |
指定提取的目录 |
-t |
列出文档内容 |
--wildcards |
使用 wildcards 匹配文件。例如 tar -xf a.tar --wildcards '*.txt' 可以提取 a.tar 中的所有 txt 文件 |
--delete |
删除文档中的文件。例如 tar -f a.tar --delete '*.txt' 可以删除 a.tar 中的所有 txt 文件 |
--exclude= |
排除文件。例如 tar -cf a.tar --exclude=*.txt . 可以创建 a.tar 时排除所有 txt 文件 |
-r |
向文档中追加文件。例如 tar -rf a.tar b.txt 可以将 b.txt 追加到 a.tar 中 |
-A |
向文档中追加另一个文档。例如 tar -Af a.tar b.tar 可以将 b.tar 追加到 a.tar 中 |
-W |
检验文档。例如 tar -Wf a.tar 可以检验 a.tar 的完整性 |
-u |
更新文档。例如 tar -uf a.tar b.txt 可以更新 a.tar 中的 b.txt 文件 |
注意:在使用 --exclude
时必须使用 =
进行连接,且 --exclude
要出现在待打包文件或目录之前,
tar -cf a.tar . --exclude=*.txt
是错误用法。
注意:在使用 -u
的时候,并不会覆盖旧的文件,而是直接追加新的文件,
这样 tar
文件中可能会有多个同名的文件,目前我并没有找到如何提取旧文件的方法。
选项 | 说明 |
---|---|
-s |
创建软连接 |
-f |
强制创建。如果软连接已经存在,会覆盖原有的软连接 |
-t |
指定连接的目标目录。ln -t dir target 与 ln target dir 效果相同 |
使用 ln target link_name
创建的时候如果 link_name
是一个目录,那么会在目录下创建一个名为 target
的文件。
ln
默认创建硬连接。
使用 rm
和 unlink
命令均可以删除软连接或者硬连接。
但是 unlink
一次只能删除一个文件,而 rm
可以删除多个文件。
ln
命令可以创建硬连接和软连接,硬连接是指多个文件指向同一个 inode
,
而软连接是指一个文件指向另一个文件。除此之外,硬连接和软连接还有以下区别:
- 软连接可以指向不同文件系统的文件,而硬连接只能指向同一个文件系统的文件。
- 软连接可以指向目录,而硬连接不能指向目录。
- 源文件被删除的时候,硬连接不会受到影响,而软连接会失效。
在 Linux
中,可以通过 ls -l
命令查看文件的硬连接数 (第二列为硬连接数),
硬连接数为 1
表示只有一个文件指向该 inode
,而硬连接数大于 1
表示有多个文件指向该 inode
。
ssh
分为 client
和 server
两部分,client
用于连接远程主机,server
用于接收远程主机的连接。
openssh-client
和 openssh-server
是 ssh
的两个主要组件。
选项 | 说明 |
---|---|
-p |
指定端口。默认端口是 22 |
-i |
指定密钥文件。默认情况下,ssh 使用 ~/.ssh/id_rsa 作为密钥文件 |
-l |
指定用户名。默认情况下,ssh 使用当前用户名作为登录用户名 |
-q |
静默模式 |
-t |
强制分配终端 |
-v |
显示详细信息。可以使用多个 v 来显示更多的信息 |
-C |
压缩传输。使用 -C 可以压缩传输的数据 |
-X |
启用 X11 受限转发。可以在本地显式远程主机的 X11 程序 |
-Y |
启用 X11 信赖转发 |
-f |
后台运行 |
-N |
不执行远程命令。通常在端口转发时使用 |
-L |
本地端口转发 |
-R |
远程端口转发 |
-D |
动态端口转发 |
-o |
指定配置选项 |
注意:对于 -l
选项,也可以不使用 -l
而是使用 user@host
的形式来指定用户名。
注意:关于端口转发可以查看 ssh
端口转发简介。
注意:-o
选项常常用于覆盖 ~/.ssh/config
文件中的配置。
例如 ssh -o "Port=2222" host_name
将会使用 2222
端口连接 host_name
,其余配置不变。
选项 | 说明 |
---|---|
-a |
指定迭代次数。越高则生成的密钥越安全,但是验证的时候也会越慢 |
-t |
指定密钥类型 |
-b |
指定密钥长度 |
-C |
添加注释 |
-c |
修改密钥的注释 |
-f |
指定密钥路经以及文件名 |
-P |
指定密钥的密码 |
-p |
修改密钥的密码 |
-l |
显示密钥的指纹 |
-H |
对 known_hosts 文件进行哈希处理 |
-R |
从 known_hosts 文件中删除指定主机的密钥 |
注意:从 open_ssh 9.5
开始默认生成的密钥是 ed25519
,而不是 rsa
。
ed25519
相较与 rsa
更加安全,且性能更好。
known_hosts
文件存储了远程主机的公钥,当第一次连接远程主机的时候,
ssh
会将远程主机的公钥存储到 known_hosts
文件中,下次连接远程主机的时候,
ssh
会检查远程主机的公钥是否和 known_hosts
文件中的公钥一致,
如果一致则连接成功,否则会提示公钥不一致。
known_hosts
文件可以很好的防止 Man-in-the-middle
攻击。
而默认情况下,known_hosts
文件的远程地址部分是以明文的形式存储的,
这样当 known_hosts
文件泄露的时候,攻击者可以直接获取到远程主机的地址与对应的公钥,
而使用 ssh-keygen -H
可以对 known_hosts
的远程地址进行哈希处理,
这样在 known_hosts
文件泄露的时候,攻击者无法直接获取到远程主机的地址与公钥的对应关系。
~/.ssh/config
文件可以用来配置 ssh
的一些选项,例如:
Host host_name
HostName host_ip
Port port
User user_name
IdentityFile ~/.ssh/id_rsa
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes
CompressionLevel 9
ForwardAgent yes
ForwardX11 yes
ForwardX11Trusted yes
TCPKeepAlive yes
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p
ControlPersist 600
UserKnownHostsFile ~/.ssh/known_hosts
StrictHostKeyChecking yes
HashKnownHosts yes
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
GSSAPITrustDNS yes
PasswordAuthentication no
PubkeyAuthentication yes
PreferredAuthentications publickey
KexAlgorithms
ProxyCommand ssh -W %h:%p proxy_address
当你拥有上面的配置后,你可以通过 ssh host_name
来连接远程主机,
而不需要指定远程主机的 ip
、port
、user
和 identity file
。
使用 *
可以对所有主机生效,可以达到修改默认配置的目的。
~/.ssh/config
中也支持通配符:
*
:匹配所有主机?
:匹配一个字符!
:排除主机
选项 | 说明 |
---|---|
-i |
指定密钥文件 |
-p |
指定端口 |
ssh-agent
用来管理用户的密钥,如果密钥被添加到 ssh-agent
后,
用户在后续登录过程中可以不输入密钥的密码。
要在当前的 shell
中启动 ssh-agent
,可以使用 eval $(ssh-agent)
。
选项 | 说明 |
---|---|
-l |
列出所有已加载密钥的指纹 |
-L |
列出所有已加载密钥的公钥 |
-d |
删除某个密钥 |
-D |
删除所有密钥 |
-x |
锁定 ssh-agent |
-X |
解锁 ssh-agent |
注意:如果命令执行过程中提示 Could not open a connection to your authentication agent
,
那么可能是因为没有启动 ssh-agent
,可以使用 eval $(ssh-agent)
启动 ssh-agent
。
sftp
是一个交互式的文件传输工具,其通过 ssh
保证文件传输的安全性。
sftp
的启动与 ssh
类似,例如 sftp user@host
。
启动后我们可以通过 help
或者 ?
列出可以使用的命令。大多 Linux
的命令都可以在 sftp
中使用。
除此之外,我们在通常的命令前面增加 l
(或 !
) 表示在本定执行,
例如 pwd
可以查看远程主机的当前目录,
而 lpwd
可以查看本地主机的当前目录;cd
可以切换远程主机的目录,
而 lcd
可以切换本地主机的目录。
如果你需要多次在本地执行某修操作,你可以使用 !
来切换到本地的 shell
,
这样就可以不用在命令前面加 l
了。执行完本地操作后想要回到 sftp
中,只需要执行 exit
即可。
使用 get
命令可以下载文件,例如 get file
表示下载 file
文件到本地主机,
而 put
命令可以上传文件,例如 put file
表示上传 file
文件到远程主机。
两个命令的使用方式与 cp
类似,对于目录需要增加 -r
选项。
直接使用 sftp
可以完成一些简单的文件传输,但是如果我们并不只是希望直接传输远程的文件,
而且还需要对远程文件进行修改,例如我们希望直接使用我们本地配置丰富的编辑器来编辑远程文件,
那么此时我们就可以使用 sshfs
来实现。
sshfs
的原理就是利用 sftp
协议将远程主机的文件挂载到本地主机上,
相信使用过类似于 NFS
的用户对这种操作并不陌生。
使用 sshfs
进行挂载:
sshfs user@host:/path/to/dir /path/to/mount_point
注意:挂载点的拥有者必须是当前用户。
如果要进行卸载,可以使用 fusermount -u /path/to/mount_point
或者 umount /path/to/mount_point
。
注意:不建议将挂载放入到 /etc/fstab
中,因为当网络不稳定时可能会进行很长时间的重试,
这样会导致系统启动时间非常漫长。
选项 | 说明 |
---|---|
-r |
递归复制 |
-P |
指定端口 |
-p |
保留文件属性 (例如修改时间等) |
-q |
静默模式 |
-v |
显示详细信息。可以使用多个 -v 来显示更多的信息 |
-C |
压缩传输 |
-i |
指定密钥文件 |
-l |
限制带宽, 单位是 Kb/s |
-3 |
通过本机在两个远端之间传输文件 |
-4 |
强制使用 IPv4 |
-6 |
强制使用 IPv6 |
使用 scp
的时候,如果在 ~/.ssh/config
中配置了主机信息,可以直接使用主机名进行传输,
例如 scp file host_name:/path/to/file
。
scp
可以一次拷贝多个文件,例如 scp file1 file2 host_name:/path/to/
。
选项 | 说明 |
---|---|
-a |
逻辑与。可用于匹配多个关键字,例如 apropos -a keyword1 keyword2 |
-e |
精确匹配 |
-w |
匹配带有 Shell 支持的通配符 |
-r |
使用正则表达式匹配 |
-l |
不依照终端宽度进行裁剪 |
-s |
指定 man 手册的节。例如 apropos -s 3 keyword 表示查找第 3 节的手册 |
man
手册的节有以下几个:
1
:命令或程序。2
:系统调用。3
:库函数。4
:特殊文件。5
:文件格式和约定。6
:游戏。7
:杂项。8
:系统管理命令。9
:内核相关。
选项 | 说明 |
---|---|
-a |
追加 |
-i |
忽略中断信号 |
tee
的作用是将标准输入的内容输出到标准输出和文件,其通常在管道中使用:
管道在进行传递的时候可能会遇到需要 root
权限的时候,
这时候就需要使用 sudo tee
从管道中读取信息并写入到文件中。
例如 echo "content" | sudo tee file
。
选项 | 说明 |
---|---|
-l |
修改用户名。例如 usermod -l new_name old_name 表示将 old_name 修改为 new_name |
-u |
修改用户 UID 。例如 usermod -u 1000 user 表示将 user 的 UID 修改为 1000 |
-o |
允许重复的 UID |
-g |
修改基本用户组。例如 usermod -g group user 表示将 user 的基本用户组修改为 group |
-G |
修改附加用户组。例如 usermod -G group1,group2 user 表示将 user 的附加用户组修改为 group1 和 group2 |
-a |
与 -G 同时使用,表示追加附加用户组 |
-c |
修改用户描述 |
-d |
修改用户主目录 |
-m |
与 -d 同时使用,表示同时移动用户主目录 |
-s |
修改用户登录 shell |
-e |
修改用户过期时间。例如 usermod -e 2025-12-31 user 表示将 user 的过期时间修改为 2025-12-31 |
-p |
设置新的密码。注意新的密码应该是加密后的密码,可以使用 openssl passwd 来生成加密后的密码,更加推荐使用 passwd 命令进行密码修改 |
-L |
锁定用户。 |
-U |
解锁用户。 |
注意:创建出来的用户默认是不会过期的。如果设置了过期时间后,可以通过 chmod -e ""
来取消。
当用户过期后,用户将无法登录,但是用户依然存在,root
可以解锁用户。
选项 | 说明 |
---|---|
-l |
以登录状态切换用户 |
-c |
执行命令。例如 su -c command user 表示以 user 用户的身份执行 command |
-s |
指定 shell 。例如 su -s /bin/bash user 表示以 user 用户的身份使用 bash shell |
-p |
保留 HOME , SHELL , USER , LOGNAME 环境变量 |
注意:使用 su
切换用户时,如果不指定用户,会默认切换到 root
用户。
注意:如果不使用 -l
选项,su
不会切换用户的环境变量,而使用 -l
的时候,以下会被依次执行:
- clears all the environment variables except
TERM
and variables specified by--whitelist-environment
- initializes the environment variables
HOME
,SHELL
,USER
,LOGNAME
, andPATH
- changes to the target user’s home directory
- sets
argv[0]
of the shell to-
in order to make the shell a login shell
选项 | 说明 |
---|---|
-l |
列出用户可以执行的命令。可以使用 sudo -l command 来检查是否可以执行某个命令 |
-U |
与 -l 一同使用,指定列出的用户而不是执行 sudo 的用户 |
-u |
指定用户执行命令。例如 sudo -u user command 表示以 user 用户的身份执行 command |
-g |
指定用户组。例如 sudo -g group command 表示以 group 用户组的身份执行 command |
-s |
指定 shell |
-k |
删除缓存的密码 |
-v |
更新记住密码时间的时间戳为当前时刻 |
/etc/sudoers
文件用于配置 sudo
的权限,只有拥有 root
权限的用户可以修改这个文件。
/etc/sudoers
文件的格式如下:
# 配置某个用户
user host=(runas[:runasgroup]) [NOPASSWD:] command
# 配置某个组下的所有用户
%group host=(runas[:runasgroup]) [NOPASSWD:] command
# 引入目录中的所有文件
@includedir dirname
对于上述的规则,方括号中代表可选项,这里给出几个实例:
user ALL=(ALL) ALL
:允许user
用户在任何主机上以任何用户的身份执行任何命令。%group ALL=(ALL) NOPASSWD: ALL
:允许group
组下的所有用户在任何主机上以任何用户的身份执行任何命令, 且不需要输入密码。@includedir /etc/sudoers.d
表示引入/etc/sudoers.d
目录下的所有文件,这是默认添加的配置, 这意味着我们对于其他用户的配置可以放在/etc/sudoers.d
目录下,并以用户名命名文件方便管理。
注意:在 @includedir
目录下的文件不能以 ~
结尾并且不能含有 .
。
这是在 /etc/sudoers.d/README
中明确指出的:
This will cause
sudo
to read and parse any files in the/etc/sudoers.d
directory that do not end in~
or contain a.
character.
注意:如果要配置多条命令应该使用 ,
作为分隔符。
推荐使用 visudo
对 /etc/sudoers
文件进行修改 (即通过命令 sudo visudo
),
visudo
会在修改后检查是否存在语法错误。
visudo
还有一些选项:
选项 | 说明 |
---|---|
-c |
检查语法错误 |
-f |
指定文件 |
选项 | 说明 |
---|---|
-a |
挂载所有在 /etc/fstab 中配置的文件系统 |
-t |
指定文件系统类型 |
-o |
指定挂载选项 |
-r |
以只读模式挂载 |
-w |
以读写模式挂载 |
--move |
移动挂载点。例如 mount --move /mnt1 /mnt2 表示将 /mnt1 移动到 /mnt2 上 |
--fake |
模拟挂载 |
常见的文件系统类型:
ext4
:Linux
文件系统。ntfs
:Windows
文件系统, 使用mount -t ntfs-3g
进行挂载。FAT32
:FAT32
文件系统,使用mount -t vfat
进行挂载。exFAT
:需要安装exfat-fuse
和exfat-utils
包,使用mount -t exfat
进行挂载。ISO
:ISO
文件系统,使用mount -t iso9660
进行挂载。nfs
:网络文件系统,使用mount -t nfs -o vers=num
可以指定版本。
注意:直接使用 mount
可以列出所有已经挂载的文件系统。
也可以使用 mount -t type
来列出指定类型的文件系统。
可以使用 blkid
命令来获取设备的文件系统类型及 UUID
,例如 blkid /dev/sda1
。
直接通过 mount
命令挂载的文件系统在系统重启后会失效,为了让文件系统在系统重启后自动挂载,
我们可以将文件系统的信息写入 /etc/fstab
文件中。/etc/fstab
文件的格式如下:
# device <mount_point> <type> <options> <dump> <pass>
/dev/sda1 /mnt ext4 defaults 0 2
其中各个字段的含义如下:
<device>
:设备文件。<mount_point>
:挂载点。<type>
:文件系统类型。<options>
:挂载选项,多个选项通过,
进行分隔。<dump>
:备份标志。0
表示不备份,1
表示备份 (需要dump
工具,通常设置为0
)。<pass>
:文件系统检查顺序。0
表示不检查,1
表示第一个检查,2
表示第二个检查 (根文件系统通常设置为1
,其他文件系统设置为2
)。
umount
用于卸载文件系统,使用方式为 umount <mount_point>
,例如 umount /mnt
。
注意:卸载文件系统的时候,如果文件系统正在被使用,会提示 device is busy
,
这时候可以使用 lsof <mount_point>
来查看哪些进程在使用这个文件系统,
然后选择是否通过 kill
命令杀死这些进程。
也可以使用 umount -l <mount_point>
在空闲时自动卸载或者使用 umount -f <mount_point>
强制卸载。
lsof
是 list open files
的缩写,用于列出系统中打开的文件。lsof
的输出包含如下几项:
COMMAND
:打开文件所使用的命令。PID
:进程ID
。USER
:进程的用户。FD
:文件描述符。TYPE
:文件类型,常见的有REG
、DIR
、CHR
、FIFO
、SOCK
、LINK
,分别代表普通文件、目录、 字符设备、管道、套接字、符号链接。DEVICE
:设备。SIZE/OFF
:文件大小或者偏移量。NODE
:inode
号。NAME
:打开的文件名。
lsof
的可用选项如下:
选项 | 说明 |
---|---|
-u |
指定用户 |
-c |
指定命令开头 |
-b |
避免获取结果时调用可能会阻塞的内核函数 |
+D |
指定目录 |
-i |
查看网络连接 |
-n |
禁止显示域名,域名全部显示为 IP 地址 |
-P |
禁止将端口号转换为服务名 |
-p |
指定进程 ID |
-U |
列出 UNIX 域套接字。TYPE 为 unix 的文件 |
-R |
同时列出父进程 ID |
-l |
显示用户的 ID |
-t |
只输出打开文件的进程 ID |
-a |
逻辑与。例如 lsof -u user -a -c command 表示查找用户为 user 且命令开头为 command 的进程 |
-d |
指定文件描述符。例如 lsof -d 1 表示查找文件描述符为 1 的文件 |
注意:使用某些选项时可以使用 ^
来表示排除某个用户,例如 lsof -u ^root
表示排除 root
用户。
注意:-i
的完整格式为:
-i[46][protocol][@hostname|@hostaddr][:service|:port],
其中 protocol
可以是 TCP
、UDP
、TCP:UDP
,hostname
可以是主机名、IPv4
地址、IPv6
地址,
service
可以是服务名、端口号。
.gitignore
文件用于指定不需要被 git
追踪的文件或目录,这些文件或目录不会被提交到版本库中。在
.gitignore
文件中可以使用 wildcards
来指定不需要被追踪的文件或目录。
.gitignore
文件还可以用于防止后续的修改被提交,例如某个文件已经被提交到版本库中,
但是后续不希望这个文件被追踪,可以将这个文件加入到 .gitignore
文件中。
这种方式常常用于设置 DEBUG
相关文件。
.gitignore
中的 wildcards
与 bash
中基本一致,
可以查看 Wildcards in Linux 来了解更多关于 wildcards
的内容。
默认情况下,.gitignore
中的条目会进行递归的忽略,如果不想进行递归忽略,
可以在条目前加上 /
表示只对当前目录生效。例如 /foo
表示只忽略当前目录下的 foo
文件或目录,
而 foo
表示忽略所有的 foo
文件或目录。
默认情况下,.gitignore
中的条目会匹配目录和文件,
如果只想匹配目录则可以在条目末尾加上 /
表示只匹配目录。例如 foo/
表示只匹配目录 foo
,
而 foo
表示匹配所有的 foo
文件或目录。你可能会有疑惑:
在
Linux
中,同一目录下的文件和目录不能够重名,这样做的意义是什么?
其实如果不进行递归匹配,确实是没有意义的,但是 build/
和 build
表示的意义是不同的,
前者表示忽略所有 build
目录,而后者表示忽略所有 build
文件或目录。
前者可以保留某个子目录下面的名为 build
的文件,而后者却做不到这一点。
当然如前面所言,我们可以使用 /build/
只忽略当前目录下的 build
目录。
在 git
中可以配置全局忽略文件,通常使用 .git
管理的仓库不需要追踪一些特定的文件,
例如 *.pyc
、*.o
等,这时候我们可以配置全局忽略文件。
全局忽略文件的配置文件是 ~/.config/git/ignore
。
在 git
中任何一个目录下都可以有一个 .gitignore
文件,这个文件会对当前目录下的文件和目录生效。
如果在父目录下有一个 .gitignore
文件,那么这个文件会对当前目录下的文件和目录生效,
但是如果当前目录下有一个 .gitignore
文件,那么这个文件会覆盖父目录下的文件。
也就是说,.gitignore
文件的优先级是从子目录到父目录逐渐降低的。全局忽略文件的优先级最低。
- 10 Practical Examples Using Wildcards to Match Filenames in Linux
- fish shell wildcards
- Linux Tutorial - Cheat Sheet - grep
- 20 grep command examples in Linux
- Linux Handbook: sort Command Examples
- 15+ Tips to PROPERLY sort files in Linux
- Linux and Unix sort command tutorial with examples
- Linux sort Command
- How to Use the awk Command on Linux
- 30+ awk examples for beginners / awk command tutorial in Linux/Unix
- 8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR
- Getting Started With AWK Command
- 25+ most used find commands in Linux
- find Linux Command Cheatsheet
- Linux Find Cheatsheet
- Find files and directories on Linux with the find command
- 10 ways to use the Linux find command
- Find cheatsheet
- Ignoring files
- cat command examples for beginners
- Linux Audit: tar cheat sheet
- 15+ tar command examples in Linux
- 10+ practical examples to create symbolic link in Linux
- 15+ scp command examples in Linux
- apropos Linux Command Explained
- 10 tee command examples in Linux
- How To Use ‘sudo’: The Complete Linux Command Guide
- Linux visudo command
- 15 usermod command examples in Linux
- Linux mount command to access filesystems, iso image, usb, network drives
- The “mount” Command in Linux
- 9 su command examples in Linux
- 15+ SSH command examples in Linux
- 15+ lsof command examples in Linux
- OpenSSH 9.5: A User-Friendly Guide to the Latest Update
- How to generate and manage ssh keys on Linux
- 10 examples to generate SSH key in Linux (ssh-keygen)
- The Complete Guide to SSH Config Files
- Beginners guide to use ssh config file with examples
- How to use the command
ssh-add
(with examples) - 5 Unix / Linux ssh-add Command Examples to Add SSH Key to Agent
- How To Use SFTP to Securely Transfer Files with a Remote Server
- libfuse/sshfs