MIT的课程:Missing Semester
介绍了Shell、vim、git等一些常用工具
检查Shell语法错误的在线网站ShellCheck
Shell
介绍
一开始介绍了一些常用的命令,大部分之前使用过。
重定向符号<
、>
,追加用>>
echo hello
cd - #回到上一个目录
cat 2.txt >> 1.txt
ls -l | tail -n3 #输出最后三行
man ls #多用man
ls -ls #-l显示详细信息,-s显示文件占用块数block,后面可跟上目录
4 -rwxrw-r-- 1 hsl hsl 132 12月 3 20:26 test
#文件占用块数、-文件d目录l链接
#权限:rwx读写执行权限,分别是拥有者、用户组、其他人
#文件数量、拥有者、用户组、时间、文件名
chmod u+x test
curl --head --silent google.com | grep --ignore-case content-length | cut --delimiter=' ' -f2
\转义字符,mkdir my\ photo
将空格转义,否则会建立两个目录
touch命令本意是修改时间戳,-a修改访问时间,-m改变修改时间,文件不存在时会默认新建
.sh文件开头#!/bin/sh
是shebang,指示解释器运行环境
/sys目录下有很多系统设置,一切皆文件!
tee命令读取标准输入,写到标准输出和文件
还讲了find、grep、curl、cut命令,后面再看一下
变量、函数
变量定义: foo=bar
, 等号左右不能有空格,否则相当于调用foo命令,=和bar作参数。
foo=bar #单引号、双引号不同
echo "$foo"
# prints bar
echo '$foo'
# prints $foo
写一个mcd命令
cat mcd.sh
mcd () {
mkdir -p $1
cd $1
}
source mcd.sh
$0
- Name of the script$1
to$9
- Arguments to the script.$1
is the first argument and so on.$@
- All the arguments$#
- Number of arguments$?
- Return code of the previous command- $$$$ - Process identification number (PID) for the current script
!!
- Entire last command, including arguments. A common pattern is to execute a command only for it to fail due to missing permissions; you can quickly re-execute the command with sudo by doingsudo !!
$_
- Last argument from the last command. If you are in an interactive shell, you can also quickly get this value by typingEsc
followed by.
orAlt+.
详细见:https://missing.csail.mit.edu/2020/shell-tools/
替换
command substitution
for file in $(ls)
process substitution
diff <(ls foo) <(ls bar)
, <( CMD ) 将执行 CMD 并将输出放在一个临时文件中,并将 <() 替换为该文件的名称。
脚本举例
举例(比较时尽量使用双方括号, why)
#!/bin/bash
echo "Starting program at $(date)" # Date will be substituted
echo "Running program $0 with $# arguments with pid $$"
for file in "$@"; do
grep foobar "$file" > /dev/null 2> /dev/null
# When pattern is not found, grep has exit status 1
# We redirect STDOUT and STDERR to a null register since we do not care about them
if [[ $? -ne 0 ]]; then
echo "File $file does not have any foobar, adding one"
echo "# foobar" >> "$file"
fi
done
- 正则表达式
? 匹配一个任意字符,* 匹配多个,{} 匹配花括号里所有
一个python脚本:
#!/usr/bin/env python3
import sys
for arg in reversed(sys.argv[1:]):
print(arg)
shebang写成这样移植性更好
函数和脚本
- 函数(平时一般叫命令?)必须和shell用同样的语言,脚本可以用任何语言,所以shebang很重要。
- 函数在读取其定义时加载一次。每次执行脚本时都会加载脚本。这使得函数的加载速度稍快一些,但是无论何时更改它们,都必须重新加载它们的定义。source命令吧
- 函数在当前的 shell 环境中执行,而脚本在它们自己的进程中执行。因此,函数可以修改环境变量,例如更改当前目录,而脚本不能。后面再看下export命令
查找
# Find all directories named src
find . -name src -type d
# *匹配0个或多个目录,在文件那匹配0个或多个字符,?只能匹配一个
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 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
# -R递归搜索目录,-n显示行号,-C显示邻近几行
grep -R -n -C 5 foobar .
其他类似grep的搜索工具 ack, ag和rg, 模糊匹配的fzf. 还有两个终端文件管理工具,nnn
和 ranger
,看着挺炫酷,后面试一试
其他
tldr工具
一些命令不能从管道中读取数据,xargs可以将标准输入转化为参数。
ls | xargs rm
课后习题
ls -lath --color=auto
, -a显示隐藏文件,-t按修改时间降序排列,-h大小显示为多少M,多少k的形式。执行marco时记录下当前目录,执行polo时回到之前记录的目录。
marco() {
export MARCO=$(pwd)
}
polo() {
cd "$MARCO"
}
- 运行err.sh脚本, 记录其输出和错误日志, 输出其出错时的运行次数
err.sh
#!/usr/bin/env bash
n=$(( RANDOM % 100 ))
if [[ n -eq 42 ]]; then
echo "Something went wrong at $(date)"
# >2是将输出重定向到文件2, &2才是标准错误
echo "The error was using magic numbers" 1>&2
exit 1
fi
echo "Everything went according to plan"
errTest.sh
#!/usr/bin/env bash
rm record.txt record2.txt
t=1
./err.sh > ./record.txt 2> ./record2.txt
while [[ $? -eq 0 ]]
do
let t++
./err.sh >> ./record.txt 2>> ./record2.txt
done
cat record.txt
echo "------"
cat record2.txt
echo "run counts: $t"
- 搜索当前文件下的html文件并打包压缩,搜索出来的内容以换行符区分 ( 排除文件名中包含空格的情况 ) .
# xargs -d 指定分隔符
find -name "*.html" | xargs -d '\n' tar -czvf archieve.tar.gz
- 递归搜索当前文件夹中的文件,按文件最后修改时间逆序排列
# stat -c或--format格式化输出 Y是UNIX时间戳,y是可读时间,n文件名
# sort -n按数值比较 -r逆序
# cut -d分隔符 -f, --fields显示什么字段,从1开始,2-取第二个及以后
# head列出前几行,默认10
find . -type f | xargs -d '\n' stat --format "%Y %y %n" | sort -nr | cut -d ' ' -f 2- | head -n 5
2022-12-28 20:46:34.869589528 +0800 ./22/33/1 3.html
2022-12-28 20:46:00.144839386 +0800 ./22/2 .html
2022-12-28 20:45:30.952572281 +0800 ./1.html
2022-12-27 23:13:16.676754571 +0800 ./record.txt
2022-12-27 23:13:16.676754571 +0800 ./record2.txt