https://missing.csail.mit.edu/
https://missing-semester-cn.g...
https://www.bilibili.com/vide...
$0
- 腳本名$1
到 $9
- 腳本的參數。 $1
是第一個參數,依此類推。$@
- 全部參數$#
- 參數個數$?
- 前一個命令的返回值$$
- 當前腳本的進程識別碼!!
- 完整的上一條命令,包括參數。常見應用:當你由於權限不足執行命令失敗時,可使用 sudo !!
再嘗試一次。$_
- 上一條命令的最後一個參數。若是你正在使用的是交互式shell,你能夠經過按下 Esc
以後鍵入 .
來獲取這個值。一個冷門的相似特性是 進程替換 ( process substitution ), <( CMD )
會執行 CMD
並將結果輸出到一個臨時文件中,並將 <( CMD )
替換成臨時文件名。這在咱們但願返回值經過文件而不是STDIN傳遞時頗有用。例如, diff <(ls foo) <(ls bar)
會顯示文件夾 foo
和 bar
中文件的區別。html
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} touch foo/x bar/y # 顯示foo和bar文件的不一樣 diff <(ls foo) <(ls bar) # 輸出 # < x # --- # > y
注意,腳本並不必定只有用bash寫才能在終端裏調用。好比說,這是一段Python腳本,做用是將輸入的參數倒序輸出:python
#!/usr/local/bin/python import sys for arg in reversed(sys.argv[1:]): print(arg)
shell知道去用python解釋器而不是shell命令來運行這段腳本,是由於腳本的開頭第一行的 shebang)。linux
在 shebang
行中使用 env
命令是一種好的實踐,它會利用環境變量中的程序來解析該腳本,這樣就提升來您的腳本的可移植性。env
會利用咱們第一節講座中介紹過的PATH
環境變量來進行定位。 例如,使用了env
的shebang看上去時這樣的#!/usr/bin/env python
。git
編寫 bash
腳本有時候會很彆扭和反直覺。例如 shellcheck 這樣的工具能夠幫助你定位sh/bash腳本中的錯誤。例如:github
locate 和 find 的對比。shell
grep 的例子:windows
rg 的例子:bash
# 查找全部使用了 requests 庫的文件 rg -t py 'import requests' # 查找全部沒有寫 shebang 的文件(包含隱藏文件) rg -u --files-without-match "^#!" # 查找全部的foo字符串,並打印其以後的5行 rg foo -A 5 # 打印匹配的統計信息(匹配的行和文件的數量) rg --stats PATTERN
有一點值得注意,輸入命令時,若是您在命令的開頭加上一個空格,它就不會被加進shell記錄中。當你輸入包含密碼或是其餘敏感信息的命令時會用到這一特性。若是你不當心忘了在前面加空格,能夠經過編輯。bash_history
或 .zhistory
來手動地從歷史記錄中移除那一項。koa
Oh-my-zsh? 新手上路看這篇:Setting up Windows Terminal, WSL and Oh-my-Zsh
macro.sh:ide
macro() { macro_dir=$(pwd) echo "I am in $macro_dir" | tee /mnt/f/code/learn/missing-semester/l2-shell-tools/macro.txt }
polo.sh:
polo() { cd "$macro_dir" || exit macro }
ex3_solution.sh:
#!/usr/bin/env bash ./ex3_problem.sh > ex3_result.txt 2> ex3_result.txt state=$? count=0 while [[ state -eq 0 ]]; do ./ex3_problem.sh >> ex3_result.txt 2>> ex3_result.txt state=$? count=$((count + 1)) done cat ex3_result.txt echo "ex3_problem ran $count times before failure"
$ tree ex4_html_folder ex4_html_folder ├── 1.html ├── 1.txt ├── a │ ├── a 1.html │ ├── a 1.txt │ ├── a 2.txt │ └── a 3.txt └── b ├── b 1.html ├── b 2.html └── b 3.html 2 directories, 9 files
參考 tldr xargs
給出的用法示例:
- Delete all files with a .backup extension (-print0 uses a null character to split file names, and -0 uses it as delimiter): find . -name {{'*.backup'}} -print0 | xargs -0 rm -v
tldr tar
給出了 tar 命令的用法示例:
- [c]reate an archive from [f]iles: tar cf {{target.tar}} {{file1}} {{file2}} {{file3}} - E[x]tract a (compressed) archive [f]ile into the target directory: tar xf {{source.tar[.gz|.bz2|.xz]}} --directory={{directory}} - Lis[t] the contents of a tar [f]ile [v]erbosely: tar tvf {{source.tar}}
所以本題解答以下:
find . -name "*.html" -print0 | xargs -0 tar cf html.tar
驗證一下:
$ tar tvf html.tar -rwxrwxrwx yzj/yzj 0 2021-01-29 15:00 ./ex4_html_folder/1.html -rwxrwxrwx yzj/yzj 0 2021-01-29 15:25 ./ex4_html_folder/a/a 1.html -rwxrwxrwx yzj/yzj 0 2021-01-29 15:25 ./ex4_html_folder/b/b 1.html -rwxrwxrwx yzj/yzj 0 2021-01-29 15:25 ./ex4_html_folder/b/b 2.html -rwxrwxrwx yzj/yzj 0 2021-01-29 15:25 ./ex4_html_folder/b/b 3.html $ mkdir ex4_html_folder_extracted $ tar xf html.tar --directory=ex4_html_folder_extracted $ tree ex4_html_folder_extracted ex4_html_folder_extracted └── ex4_html_folder ├── 1.html ├── a │ └── a 1.html └── b ├── b 1.html ├── b 2.html └── b 3.html 3 directories, 5 files
上面的解法是把 find 命令的輸出的分隔符,由本來的換行符變成了 null,而後讓 xargs 也用 null 做爲分隔符。也能夠用 -d 選項指定換行符做爲分隔符,所以另解以下:
find . -name "*.html" | xargs -d "\n" tar cf html.tar
# 按最近修改順序列出文件 $ find . -type f -print0 | xargs -0 ls -lt --color -rwxrwxrwx 1 yzj yzj 10240 Jan 29 15:27 ./html.tar -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/a/a 1.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder_extracted/ex4_html_folder/a/a 1.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/a/a 3.txt' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/a/a 2.txt' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/a/a 1.txt' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/b/b 1.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/b/b 2.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder/b/b 3.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder_extracted/ex4_html_folder/b/b 1.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder_extracted/ex4_html_folder/b/b 2.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:25 './ex4_html_folder_extracted/ex4_html_folder/b/b 3.html' -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:01 ./ex4_html_folder/1.txt -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:00 ./ex4_html_folder/1.html -rwxrwxrwx 1 yzj yzj 0 Jan 29 15:00 ./ex4_html_folder_extracted/ex4_html_folder/1.html -rwxrwxrwx 1 yzj yzj 837 Jan 29 10:14 ./ex3_result.txt -rwxrwxrwx 1 yzj yzj 291 Jan 29 10:11 ./ex3_solution.sh -rwxrwxrwx 1 yzj yzj 205 Jan 29 09:58 ./ex3_problem.sh -rwxrwxrwx 1 yzj yzj 58 Jan 29 09:52 ./macro.txt -rwxrwxrwx 1 yzj yzj 49 Jan 29 09:48 ./polo.sh -rwxrwxrwx 1 yzj yzj 129 Jan 29 09:44 ./macro.sh -rwxrwxrwx 1 yzj yzj 50 Jan 28 21:41 ./mcd.sh -rwxrwxrwx 1 yzj yzj 509 Jan 28 21:10 ./example.sh # 找到最近修改的文件 $ find . -type f -print0 | xargs -0 ls -lt --color | head -n1 -rwxrwxrwx 1 yzj yzj 10240 Jan 29 15:27 ./html.tar