shell
用powerShell有些也行
basics
basic commands
在执行程序时在后面使用 -h
或 --help
标记看提示; 在前面使用man
查看手册;history
打印历史命令
date
打印日期、时间echo [参数1]
打印[参数1]; 注意shell中用空格分隔的被认为是不同参数, 例如echo [参数1] [参数2]
; 如果需要传递的参数包括空格, 用转义符号\
;echo
实际上是一个程序,可以直接用路径替代echo
来执行$PATH
环境变量, 是用:
分隔的地址们which
确定程序名(e.g.echo
)代表的实际程序地址
navigation
shell 中的路径是一组被分割的目录.
在linux中绝对路径由/
分割, 相对路径由\
分割.
linux中, 路径开头的/
代表的是系统的根目录,所有的文件夹都包括在这个路径之下, e.g. /bin/echo
.
Windows中路径用\
分割, 这是因为在Windows上每个盘都有一个根目录(例如:C:\
)
pwd
当前工作目录ls
list目录下的所有文件(默认当前目录);ls -l [目录]
;ls *.sh
globbing所有.sh
后缀名文件;ls [文件名]?
仅列举名字多一位的文件(?
占一位);ls [文件名]+tab+tab
可以筛选出包含这个名字的文件文件的属性:
drwxr-xr-x
d
表示目录; 此后三位一读, 依次为文件所有者,用户组与所有人的权限;r = read, w = write, x = execute
powerShell中mode有d - Directory, a - Archive, r - Read-only, h - Hidden, s - System, l - Reparse point, symlink, etc
cat
读出文件内容mv
moverm [文件]
removecp [源] [末]
copymkdir
make directoryfind
递归查找文件# 查找所有名称为src的文件夹 find . -name src -type d # 查找所有文件夹路径中包含test的python文件 find . -path '*/test/*.py' -type f # 查找前一天修改的所有文件 find . -mtime -1 # 查找所有大小在500k至10M的tar.gz文件 find . -size +500k -size -10M -name '*.tar.gz' # 删除全部扩展名为.tmp 的文件 find . -name '*.tmp' -exec rm {} \; # 查找全部的 PNG 文件并将其转换为 JPG find . -name '*.png' -exec convert {} {}.jpg \;
grep
查找文件内容grep "^\(gcc\|g++\)" # 只保留gcc或g++开头的行(正则表达式!)
input and output flow
默认的输入输出流是终端
[命令] < [输入地址]
[命令] > [输出地址]
最简单的重定向到文件(直接替换原有内容), e.g.cat < hello.txt > hello2.txt
[命令2] >> [输出地址]
(在原来的基础上)追加内容[程序1]|[程序2]|[程序3]
管道,像这样连接多个程序
root user
sudo
以superuser的身份执行
如果向/sys
下的系统文件写入,必须作为根用户
$ sudo find -L /sys/class/backlight -maxdepth 2 -name '*brightness*'
#/sys/class/backlight/thinkpad_screen/brightness
$ cd /sys/class/backlight/thinkpad_screen
$ sudo echo 3 > brightness
#An error occurred while redirecting file 'brightness' open: Permission denied
$ echo 3 | sudo tee brightness
#correct 现在sudo是用于写入了
grammar
foo=bar
定义变量,注意没有空格(空格会被识别成参数)!echo "$foo"
或echo $foo
得打印变量中的内容(转义),echo '$foo'
打印原义字符串(无转义)foo=$(pwd)
命令替换(command substitution).这里pwd
命令的输出($(pwd)
)被写入foo
变量,通过STDIN传递返回值diff <(ls foo) <(ls bar)
进程替换(process substitution).<(ls foo)
将结果输出到一个临时文件,通过文件传递返回值- 善用一些常用的参数
mcd () { # make a directory and move to it mkdir -p "$1" cd "$1" }
函数.
source mcd.sh
加载并执行函数$0
脚本名;$1
到$9
即其[参数1]至[参数9]$@
所有参数;$#
参数个数$?
前一个命令的返回值,e.g.执行完上一个命令后,echo $?
STDERR可以输出error code(0 fortrue
, 1 forfalse
)$$
当前脚本的进程识别码!!
完整的上一条命令,包括参数,e.g. 权限不足执行命令失败时,可以使用sudo !!
再尝试一次。$_
上一条命令的最后一个参数.如果你正在使用的是交互式 shell,你可以通过按下Esc
之后键入.
来获取这个值。 - 短路运算符(short-circuiting).与退出码搭配使用,e.g.
false || echo "Oops, fail" true || echo "Will not be printed" true && echo "Things went well" false && echo "Will not be printed" false ; echo "This will always run"
||
&&
代码按顺序从前往后执行,直至满足逻辑(如果第一个已经确定逻辑,之后的不会执行);;
代码并列(均会)执行 - 这段脚本遍历参数,使用
grep
搜索字符串foobar
,如果没有找到,则将其作为注释追加到文件中。#!/bin/bash echo "Starting program at $(date)" echo "Running program $0 with $# arguments with pid $$" for file in "$@"; do grep foobar "$file" > /dev/null 2> /dev/null # 如果模式没有找到,则grep退出状态为 1 # STDOUT and STDERR redirected to NULL are discarded if [[ $? -ne 0 ]]; then #-ne: not equal (\approx !=) echo "File $file does not have any foobar, adding one" echo "# foobar" >> "$file" fi done
- 通配(globbing).分别使用
?
和*
来匹配一个或任意个字符,e.g.rm foo*
removes files that start withfoo
.花括号{}
,自动展开一系列子串convert image.{png,jpg} # 会展开为 convert image.png image.jpg cp /path/to/project/{foo,bar,baz}.sh /newpath # 会展开为 cp /path/to/project/foo.sh /path/to/project/bar.sh /path/to/project/baz.sh /newpath mv *{.py,.sh} folder # 会移动所有 *.py 和 *.sh 文件 mkdir foo bar # 排列组合,创建foo/a, foo/b, ... foo/h, bar/a, bar/b, ... bar/h这些文件 touch {foo,bar}/{a..h}
#!/usr/local/bin/python
或#!/usr/bin/env python
shebang行告诉内核在shell中也用python解释器.import sys
是与shell合调所需要的库一些工具:shelldeck可以详细解释错误;tldr给出例程
command line environment
- 结束进程
^c
shell 会发送一个SIGINT信号到进程^\
发送SIGQUIT信号kill -TERM <PID>
发送更好用的SIGTERM信号- 关闭终端发送SIGHUP信号
- SIGKILL信号不能被进程捕获并且会马上结束该进程,但会有副作用
- 暂停进程
^z
发送SIGTSTP信号(terminal stop)fg
前台继续bg
后台继续jobs
列出当前终端会话中尚未完成的全部任务.可以使用 pid 引用任务,使用百分号 + 任务编号选取任务,使用$!
选择最近的一个任务- e.g.
nohup sleep 2000 &
防止SIGHUP终止后台(&后缀)进程;对已经运行的程序可以使用disown
-
终端多路复用
Action Keys combinations start tmux tmux quit(detach) a session d attach and detach session tmux attach/detach, tmux attach/detach -t [name] list sessions tmux ls create a session tmux new -s [name] to travel among sessions s kill a session tmux kill-session -t [name] Create window c Rename window , Switch to previous window p Switch to next window n Obtain navigable windows list w Kill a window & Split vertically % Split horizontally " visualise pane numbers q Move pane to the left { Move pane to the right } Switch panes layout spacebar navigating ↑ ↓ ← → kill a pane x
git
repository
在一切之前, SSH key配置: https://git-scm.com/downloads
- 在项目目录下执行
git init
以创建子目录.git
,e.g.git add *.c git add LICENSE git commit -m 'initial version'
- 或者
git clone [网址] [自定义名]
.gitignore
文件中#
为注释,用globbing# 忽略所有的 .a 文件 *.a # 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件 !lib.a # 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO /TODO # 忽略任何目录下名为 build 的文件夹 build/ # 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt doc/*.txt # 忽略 doc/ 目录及其所有子目录下的 .pdf 文件 doc/**/*.pdf
status
git status
,git status --short
或git status -s
给出更简洁- new file untracked:
add
->staged;staged:commit
->unmodified(up-to-date); - existing unmodified: edit->modified,
rm
->untracked; modified:stage
->staged;commit
->unmodified - 如果
add
后又修改了? 需要再add
后stage&commit
,不然保存的是老版本 it commit -a
以跳过staged直接全部提交trackedgit rm -f
强制删除;git rm --cached [文件名]
仅停止跟踪不删除原文件;git rm [目录]/\*.[后缀名]
,git rm \*[名字结尾]
进行批量删除git mv file_from file_to
move可以用来重命名git diff
给出gnu diff format,对比当前文件与暂存快照的差异;git diff --stage
对比暂存文件与提交文件;git diff --cached
看已暂存的变化git log --author='author' --since=2.weeks
,git log --pretty=format:"%h %s" --graph
看提交历史- 替代第一次提交
$ git commit -m 'initial commit' $ git add forgotten_file $ git commit --amend
取消暂存,建议小心点用
git reset HEAD [已暂存文件]
;撤销修改git checkout [修改后文件]
- tag
branches
每一个type object = blob | tree | commit
,其中blob
保存文件快照,tree
记录目录,commit
包含一个指向上次提交对象(父对象)的指针.
Git 的分支本质上是指向提交对象的可变指针.默认分支master
指向最后一次提交,特殊指针HEAD
指向当前分支,分支独立不干扰,注意用git checkout [分支]
切换.
# 新建并切换分支
$ git checkout -b hotfix
# 将hotfix分支合并到master,指针右移(fast-forward)
# <--hotfix<--master
$ git checkout master
$ git merge hotfix
# 删除(抽离)hotfix
git branch -d hotfix
如果合并有文件冲突,可以用git status
看,用git mergetool
解决