写点什么

Shell 的技巧小总结 (MIT Missing Semester)

用户头像
AndersonKim
关注
发布于: 2020 年 06 月 13 日
Shell的技巧小总结(MIT Missing Semester)

最近经常会抽出一些时间来看The Missing Semester of Your CS Education ,MIT 2020的课程,课程链接如下:https://missing.csail.mit.edu/

看不了油管的朋友可以在下面看b站的视频。



整个课程提供了不少各种各样CS 工具的小技巧,有些工具平常经常使用,但只会用其最基础的功能,对于不少进阶用法却没有深层钻研。



就借着这个机会,把一些个人觉得比较好用的小技巧总结一下(过于基础的就不写了)

下面,让我们开始Lecture 1&2 吧! Let's go!


连接程序的方法

在shell中,程序有两种主要的连接形式: input stream和output stream, 当程序想要去读input的时候,他们会从input stream中读取数据,当他们想要输出的时候会输出到output stream中。



对于这样的输入输出, 我们是否可以重定向呢?

回答是: 当然可以。 重定向有如下两种方法:< 和 |



  • 先说<

  • <主要是对文件形式的重定向。主要方式是< file 和 > file。 直观上也很好理解, 第一个对应着从file输出为program的input stream, 而第二项则代表着将output stream输出到file

  • >> 这个符号是用来将输出追加到原始文件末尾的

echo hello > hello.txt



  • | 是用来绕开文件,直接将各个程序链接到一起,来形成酷炫的功能。

  • 其中管道有一个特别有意思的应用场景:如果我们需要更改需要sudo权限的系统设置,这时候如果直接sudo echo 3 > brightness 是不行的,因为 >这样的命令是由shell完成的,不是一个单独的程序。这里shell会在sudo echo得到output之前,以用户的身份打开brightness这个文件,这样当然是没有权限的,从而报错了,但我们可以很好地利用管道来解决这个权限问题。

  • echo 3 | sudo tee brightness 就是一个很好的解决方案,tee以root的身份打开brightness来进行修改, 同时也会给一份输出到shell的output stream里。

  • 同时对于只接受参数的程序来说,我们可以使用xargs这个参数来接受上一个程序的管道输出,示例如下: pgref sql | xargs kill -9 这样就解决了参数的管道输出问题。

shell脚本

这里以bash下面的语言规范为例:

一. ''和""的区别:

foo=bar
echo "$foo"
# prints bar
echo '$foo'
# prints $foo



二. bash的函数

mcd () {
mkdir -p "$1"
cd "$1"
}

其中:



  • $0 - 脚本名字

  • $1 to $9 - 脚本的参数. $1 是第一个参数.

  • $@ - 所有的参数

  • $# - 参数的个数

  • $? - 返回值(上面的代码是否成功)

  • $$ - 现在的脚本pid

  • !! - 上一条输入的命令. 常见的用法是上一条命令输入错了: 比如忘记输入了sudo,那么就可以输入sudo !!

  • $_ - 上一条命令的最后一个参数。



三. 命令行作为参数

3.1 command substitution(指令替换)

$(command) #这里就是得到command的output,然后将其替换到这里面

3.2 process substitution(过程替换)

< (CMD) #会将cmd执行并将结果放在一个临时文件里,然后会将<()替换成文件名,这样就适用于针对文件的操作



例如:

diff <(ls foo) <(ls bar)

就将foobar文件夹中的差别打印出来了



四.terminal中执行脚本语言

注意shell中不一定只可以执行bash语言,python脚本也可以直接在shell中运行

#!/usr/local/bin/python
import sys
for arg in reversed(sys.argv[1:]):
print(arg)

只需要在第一行加入shebang line, 同时shebang还可以使用env 来帮助解决找到路径问题,避免路径错误。例如这里的第一行就可以替换为 #!/usr/bin/env python



五. 函数和脚本的区别



  • bash中的函数必须和shell的语言相同,但脚本语言任意,只需要配置好相应的shebang就可以了

  • 函数只需要load一次,就可以反复执行,但是脚本却需要在每次他们要被用的时候,反复执行,这样其实函数是load更快的,但是每次修改他们之后,都需要重新load.

  • 函数被执行在当前的shell环境中,而脚本是在他们自己的进程下,所以函数可以更改环境白能量,但是脚本不可以。






shell的工具总结

一. TLDR

TLDR是一个很好用的工具,相较于man提供的繁杂手册,TLDR给出了最常用的example。



tldr tar



的结果如下:



二. Finding Files

这里一个非常好用的工具是find, 示例如下:



# Find all directories named src
find . -name src -type d
# Find all python files that have a folder named test in their path
find . -path '*/test/*.py' -type f
# Find all files modified in the last day
find . -mtime -1
# Find all zip files with size in range 500k to 10M
find . -size +500k -size -10M -name '*.tar.gz'



同时find可以在找到file的同时,对于找到的文件执行一系列操作:



# Delete all files with .tmp extension
find . -name '*.tmp' -exec rm {} \;
# Find all PNG files and convert them to JPG
find . -name '*.png' -exec convert {} {}.jpg \;



三. Finding Code

grep 是用来匹配file的内容:



  • grep -C 用来找到matching line的上线

  • grep -R 来迭代步入文件夹找到对应的匹配



现在又有了叫ripgrep的工具,比grep 要方便很多



# Find all python files where I used the requests library
rg -t py 'import requests'
# Find all files (including hidden files) without a shebang line
rg -u --files-without-match "^#!"
# Find all matches of foo and print the following 5 lines
rg foo -A 5
# Print statistics of matches (# of matched lines and files )
rg --stats PATTERN



四. finding shell commands

我们经常还有寻找特定的command的需求:



  • history可以让你找到整个shell history, history | grep find 可以打印出含有find的历史命令

  • CTLR+R 也是一个找历史命令的好方法,当你输入一个substring的时候,你可以不断使用^+R来找到历史上对应的匹配字符串。

  • 还有些zsh自带的插件,比如auto-suggestions也是一个很好的方案。



五. 快速找到文件夹

  • 可以使用autojump这一类的插件来快速挑战

  • 同时tree, boot也是很好用的方法



总结:

工欲善其事必先利其器。对于程序员来说,这些基础的工具是每天都必须进行交互的,所以花适当的时间来不断钻研他们的进阶用法绝对是值得的!



发布于: 2020 年 06 月 13 日阅读数: 84
用户头像

AndersonKim

关注

UMich CSE PhD Candidate 2018.09.17 加入

16级中科大少年班学院计算机方向学生,20 fall将前往密歇根安娜堡大学读Computer Science and Engineering PhD

评论

发布
暂无评论
Shell的技巧小总结(MIT Missing Semester)