link(11/26)
hard link(硬链接)
ln
,在两个文件间创建链接,默认为硬链接。
# 创建一个硬链接 $ ln ubun.txt ubunln.txt
查看ubun.txt
和ubunln.txt
的文件属性,发现都是一样的,确定是硬链接
在 stat
命令中,可发现硬链接文件与源文件
其 Links 变成了 2,Links 代表硬链接的个数。
具有相同的 Inode:657204
具有相同的 Size 及属性
symbol link(软链接)
ln -s
,在两个文件间创建符号链接,符号链接也被称为软链接。
cat/head/tail(11/27)
cat
cat
,concatenate
缩写,concatenate and print files
连接文件并打印至标准输出(stdout)。
$ cat README.md # 也可以打印控制字符,比如 Tab、换行等不可见字符 # -v: 打印 <Ctrl-X> # -e: 打印换行 # -t: 打印 TAB $ cat -vet README.md # 打印行号 $ cat -n READEME.md
head
head
,读取文件或者标准输入的前 N 行或前 N 个字节。
# 输出文件前 10 行内容 $ head -10 README.md # 与以上命令同义 $ head --lines 10 READEME.md # 输出文件前 10 个字节 $ head -c 10 READEME.md
tail
tail
,读取文件或者标准输入的最后 N 行或最后 N 个字节。
# 输出文件后 10 行内容 $ tail -10 README.md
但是它与 head
最大不同的一点是:--follow
,简写为 -f
。它可以实时打印文件中最新内容。
在调试日志时非常有用:日志一行一行追加到文件中,而 tail -f
可以实时打印追加的内容。
$ tail -f log.json # 如果为了做实验,可再打开一个窗口通过 >> 重定向追加内容至 log.json,具体查看下一章 $ echo test >> log.json
pipe|redirection(11/28)
pipe
|
构成了管道,它将前边命令的标准输出(stdout)作为下一个命令的标准输入(stdin)。
标准输出
可以理解成将数据打印到终端上面,标准输入
可以理解成在终端中输入
# 读取 package.json 内容,读取前十行,再读取最后三行 $ cat package.json | head -10 | tail -3
stdin/stdout
在上边提到标准输入(stdin)与标准输出(stdout),其实,stdin/stdout 就是特殊的文件描述符。
stdin
,fd = 0,直接从键盘中读取数据stdout
,fd = 1,直接将数据打印至终端stderr
,fd = 2,标准错误,直接将异常信息打印至终端
redirection
>
:将文件描述符或标准输出中内容写入文件>>
:将文件描述符或标准输出中内容追加入文件
# READEME.md 内容为 hello,这里的文件描述符就是标准输出 $ echo hello > README.md # READEME.md 内容最后一行为 hello $ echo hello >> README.md
heredoc
在许多官方文档中的命令中,我们经常可以看到以下用法
$ cat <<EOF > READEME.md ...
其意思是将标准输入时的内容,写入到 README.md 中。
其中 <<EOF
,称作 Here Document
,当最终写入 EOF(End of file)时,则 heredoc 会停止输入。
日志重定向
/dev/null 是一个空文件,对于所有的输入都统统吃下,化为乌有,有时,为了不显示日志,可将所有标准输出重定向至 /dev/null。
/dev/null在类Unix系统中是一个特殊的设备文件,它丢弃一切写入其中的数据,读取它则会立即得到一个EOF。 在程序员行话,尤其是Unix行话中,/dev/null被称为比特桶或者黑洞。可以理解成充当的是垃圾箱的功能。
但此时,stderr 仍然会打印至屏幕。如果后边跟一个 2>&1,表示将 stderr (fd 为2) 重定向至 &1 (fd===1 的文件,及 stdout),同标准输出一同重定向至 /dev/null,也就是标准输出日志与标准错误日志都不显示。
# 不显示 stdout 内容 $ echo hello > /dev/null # 既不显示 stdout,也不显示 stderr # 此时 hello 文件不存在,如果没有后边的 2>&1,仍然会有日志打印至屏幕,如果加上 2>&1,则 stderr 也不显示 $ cat hello > /dev/null 2>&1
glob(11/29)
glob,global
的简写,使用通配符来匹配大量文件。比如 rm *.js
就可以删除当前目录所有 js 文件。glob
拥有以下基本语法
*
:匹配0个及以上字符?
:匹配1个字符[...]
:range,匹配方括号内任意字符**
:匹配0个及多个子目录(在 bash 下,需要开启 globstar 选项)
root@VM-16-6-ubuntu:~/data# ls -lah *[ubu]*.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubunln.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubun.txt root@VM-16-6-ubuntu:~/data# ls -lah *.txt lrwxrwxrwx 1 root root 8 Nov 26 10:00 datalns.txt -> data.txt -rw-r--r-- 1 root root 0 Nov 21 12:53 data.txt -rw-r--r-- 1 lighthouse lighthouse 68 Nov 28 10:30 try1.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubunln.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubun.txt
brace
brace
,用以扩展集合、数组等,有以下语法。
set
:{a,b,c}
range
:{1..10}
,{01..10}
step
:{1..10..2}
$ echo {a,b,c} a b c # range: 输出 01 到 10 $ echo {01..10} 01 02 03 04 05 06 07 08 09 10 # step: 输出 1 到 10,但是每一步需要自增 2 $ echo {1..10..2} 1 3 5 7 9 # step: 输出 1 到 10,但是每一步需要自增 3 $ echo {1..10..3} 1 4 7 10 # step: 输出 10 到 1,但是每一步需要自减 2 $ echo {10..1..2} 10 8 6 4 2 $ echo {a..z} a b c d e f g h i j k l m n o p q r s t u v w x y z
列出所有以json
txt
结尾的文件
root@VM-16-6-ubuntu:~/data# ls -lah *.{json,txt} -rw-r--r-- 1 root root 0 Nov 29 09:29 data.json lrwxrwxrwx 1 root root 8 Nov 26 10:00 datalns.txt -> data.txt -rw-r--r-- 1 root root 0 Nov 21 12:53 data.txt -rw-r--r-- 1 lighthouse lighthouse 68 Nov 28 10:30 try1.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubunln.txt -rw-r--r-- 2 ubuntu ubuntu 0 Nov 25 20:38 ubun.txt
find(11/30)
在 find
中,用以验证某个文件是否匹配的条件称为 Test
,一般基于文件的属性进行查找,而文件的属性,可通过 stat
命令进行获得。
-name
:根据文件名查找,注意文件名需要使用引号括起来-mtime
:根据mtime
属性查找-perm
:根据权限进行查找-type
:根据文件类型进行查找-inum
:根据inode
属性查找,用以寻找硬链接非常有用
另外,对于某些数字属性,还有 +
/-
用以比较
+n
:大于 n,如find. -mtime +30
,递归遍历最近修改时间大于 30 天的文件-n
:小于 n,如find. -mtime -30
,递归遍历最近修改时间小于 30 天的文件
# 注意,如果文件路径名使用 glob,则需要使用引号括起来 $ find . -name '*.json' # 在当前目录递归查找包含 hello 的文件 $ find . -name '*hello*' # 在当前目录递归查找修改时间大于 30 天并且小于 60 天的文件 # 其中数字以天为单位,+ 表示大于,- 表示小于 # +30: 大于30天 # -60: 小于60天 $ find . -mtime +30 -mtime -60 # 在当前目录递归查找权限 mode 为 777 的文件 $ find . -perm 777 # 在当前目录递归查找类型为 f/d/s 的文件 $ find . -type f $ find . -type d $ find . -type s # 在当前目录递归查找 inode 为 10086 的文件 # 一般用以寻找硬链接的个数,比如 pnpm 中某一个 package 的全局路径在哪里 $ find . -inum 10086 # 寻找相同的文件(硬链接),与以上命令相似 $ find . -samefile package.json # 仅在当前目录递归检索 $ find . -mindepth 1 -maxdepth 1 -name '*.json'
ag(12/1)
根据文件内容进行搜索
$ ag hello
vim
模式
normal。普通模式,刚进入 vim 的默认模式,也是最重要的模式。 确保大部分操作在普通模式下完成,而不是插入模式。
insert。插入模式。在普通模式下通过 i 进入插入模式,在插入模式下进行文字编辑。
command。命令模式。在普通模式下通过 : 进入命令模式,在命令模式下执行命令。
insert mode commands
一般来说,通过 i
进入 insert mode
,但除此之外,还有一些更好用的进入插入模式的命令。
i
: 进入插入模式,并定位光标至当前字符之前I
: 进入插入模式,并定位光标至当前行首a
: 进入插入模式,并定位光标至当前字符之后A
: 进入插入模式,并定位光标至当前行尾o
: 进入插入模式,当前光标之后新建一行,并定位光标至后一行O
: 进入插入模式,当前光标之前新建一行,并定位光标至前一行
normal mode commands
一般来说,通过 <esc>
可退出 insert mode
,但是基于两方面考虑,一般不使用该键
<esc>
过于偏远,按键不方便。- 在 VSCode/Codepen/CodeSandbox 及命令行的 vi 模式下,
<esc>
可能与其它快捷键发生冲突。
可使用 <ctrl-c>
或者 <ctrl-[>
进行替代。
grep(12/3)
昨天考完了编译原理,摆烂了一会,今天继续学习一点。vim的操作单独写篇分享吧,关键是要多练习vim,才能熟练的操作它。
grep
只是一个正则的工具,具体还得靠你对正则的掌握程度。
- 找出和root有关的行,
-i
可以是忽略大小写,-c
可以统计出多少行和root
有关
grep "root" default bash
root$ grep "try" -i -c default
4
- 去除注释开头的行,
-v
表示方向匹配
grep '^#' default -v
- 去除注释并且去除空行,我们可以使用管道连接符
$ grep '^#' default -v | grep '^$' -v
- 去除以空格开头的注释行
$ grep -v "^\s*#"
wc(12/7)
艰难的期末周终于度过,又可以安安心心学习了。
wc
,word count
的缩写。用以统计文本中字符、单词及行数。
$ wc package.json 153 458 7432 package.json # -l:--lines 行数 $ wc -l package.json 153 package.json # 如果仅仅想显示行``数 $ cat package.json | wc -l 153 # -w:--words 词数 $ wc -w package.json 458 package.json # -c:--bytes 字节数 $ wc -c package.json 7432 package.json # -m:--chars 字符数 $ wc -m package.json 7432 package.json
tr
tr
,全局替换文件。tr
“从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备”,因为它并不能改变文件内容啊。
# 小写转化为大写 $ echo hello | tr a-z A-Z HELLO # hello -> world $ echo hello | tr hello world world # 去除字符串中的多余空格 # -d:删除特定字符 $ echo " hello " | tr -d " "
sed(12/8)
sed
是一个用来筛选与转换文本内容的工具。一般用来批量替换,删除某行文件
sed命令详解
每个 sed 命令,基本可以由选项,匹配与对应的操作来完成
# 打印文件第三行到第五行 # -n: 选项,代表打印 # 3-5: 匹配,代表第三行到第五行 # p: 操作,代表打印 $ sed -n '3,5p' file # 删除文件第二行 # -i: --in-place,选项,代表直接替换文件 # 2: 匹配,代表第二行 # d: 操作,代表删除 $ sed -i '2d' file # -i可以直接修改文件,所以重要文件修改前我们需要备份一下 # 备份文件可以用cp,rsync等信息,也可也通过-i.bak 来备份文件,它会自动备份以bak结尾的文件 $ sed -i.bak '2d' a.txt
关键选项
-n: 仅显示处理之后的结果 -i: --in-place,原地替换文本内容 -f: --file,指定 sed 脚本文件,包含一系列 sed 命令
小练习(12/9)
- 过滤出含有 hello 字符串的行
# 我们可以通过之前学习的grep命令来过滤 $ grep hello a.txt # 用sed命令,不过要稍微麻烦一点 $ ubuntu@ubuntu:~/sed$ sed -n '/hello/p' a.txt hello helloworld today
- 删除含有hello字符串的行,
ubuntu@ubuntu:~/sed$ sed -n '/hello/p' a.txt hello helloworld today ubuntu@ubuntu:~/sed$ sed '/hello/d' a.txt jsonp cors hhh
3.替换字符串
$ sed -i.bak 's#hello#HELLO#g' a.txt
dig(12/10)
解析某个域名的 IP 地址
dig www.bilibili.com # 仅仅返回 IP 地址 $ dig +short www.bilibili.com
可以看出 b站 应该是做了负载均衡
12/30
终于过完了考试周,还有疫情的影响,已经断更好久了,接下来我们从学习shell开始吧!
shell
sh
sh,即 Shell Command Language
的简称,是由 Shell Command Language 表述的一份规范。
而 bash
/zsh
/fish
/dash
等是基于该规范的实现。但 sh 的规范有些简陋,因此 bash
/zsh
不仅实现了基本功能,甚至对 sh 进行了功能的扩展。
比如在 sh 规范中并没有数组,在 bash
/zsh
中均对数组进行了实现。
比如在前端中,
ESMAScript
就是一份规范,而在 Node.js 与浏览器环境中的 Javascript 甚至Typescript
是对它的实现。
在 linux 中,拥有各种各样的 shell,比如 dash、bash、zsh 等。 如果将服务器作为个人开发服务器,则很适合将 zsh 作为个人的默认 shell。
zsh
安装zsh教程:segmentfault.com/a/119000001…
# 安装zsh sudo apt-get install zsh wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | sh vim ~/.zshrc # 更新配置文件 source ~/.zshrc
变量定义
h = "hello" echo $h echo "abc-$h" echo "abc-$habc" echo "abc-${h}world" # 分别打印,最好用{}表示是一个变量 # hello # abc-hello # abc- # abc-helloworld
for循环
批量创建文件
我们可以先用echo
打印要执行的字符串,然后再执行那个命令,防止出错
批量修改文件
将week -> charapter
- 先取得文件名称
- 去除week
- 在前面加上charapter
- 打印出指令字符串
- 发现没有问题,直接执行就欧克了