Filter
Filter 常用於從大量文本、數據中提取需求的部分。下面介紹幾個常用的 filter 命令。
cut
$ cut -c 5-8 textfile.txt # 切出 textfile.txt 中每行的第 5 到第 8 個 character
$ cut -f2-4 -d',' textfile.txt # 切出 textfile.txt 中每行的第 2 到第 4 塊 field,field 由 delimiter “,” 確定
$ cut -f2,4 -d'|' textfile.txt # 切出 textfile.txt 中每行的第 2 、第 4 塊 field, field 由 delimiter “|” 確定
uniq
$ sort | uniq -c # aggregation (帶 count),類似 SQL 中的 GROUPBY
egrep
$ egrep -o <pattern> textfile.txt # 只返回 match pattern 的部分
$ egrep -x <pattern> textfile.txt # 只有文件的某行 (line) fully match pattern 的時候才返回
$ egrep -w <pattern> textfile.txt # 只有文件的某字 (word) fully match pattern 的時候才返回
wc
$ wc -l textfile.txt # 返回行數計數
$ wc -m textfile.txt # 返回char計數
$ wc -w textfile.txt # 返回word計數
tr
$ tr <srcChars> <destChars> # 將輸入字符中含有 srcChars 的字符對應替換成 destChars
$ tr 'a-z' 'A-Z' # 將輸入字符的小寫字母轉為大寫
$ tr -d ' ' # 刪除輸入字符中所有的空格
$ tr -cs 'a-zA-Z0-9' '\n' # 切出在 SET 'a-zA-Z0-9' 中的連續字符,並按行輸出
sed
$ sed 's/regex/replacement/ig' # 將 match regex 的部分全部替換成 replacement
cat
$ cat >new_textfile.txt<<eof # 新建並從 stdin 按行寫入文件 new_textfile.txt,直到遇到 eof 結束
$ cat >>new_textfile.txt<<eof # 從 stdin 按行連接寫入文件 new_textfile.txt,直到遇到 eof 結束
Shell Script 入門
介紹 Shell 的一些常識和基本用法。
准備工作
Shell 腳本文件頭
#!/bin/bash # 告訴 Linux 該文件用 bash 運行
可執行模式
$ chmod +x shell_script.sh # 修改 shell_script.sh 為可執行文件
常用命令
SSH
遠程連接服務器(以 AWS 為例)
如果要連接 AWS, 需要聯系管理員拿到私鑰文件(擴展名為 .pem)。
$ ssh -i "private-key.pem" user_name@domain_name
如果想在 AWS 上運行 jupyter,tensorboard 等任務,可以使用 local forwarding 功能,將本地操作轉發到遠端服務器:
$ ssh -i "private-key.pem" <local-port>:127.0.0.1:<remote-port> user_name@domain_name
STDIN
$ read a_str_variable # 從 stdin 讀取字符串存入 a_str_variable 變量
$ read -t 3 a_str_variable # 3s 內無輸入則退出(返回值 142)
$ read -s a_str_variable # 不顯示輸入字符,輸入密碼等機密信息時使用
$ read -p "Name? " # 相當於 Python 中的 input("Name? ")
$ read -r a_str_variable # 當輸入的字符中含 “\” (反斜杠)時,保留 “\”。如果沒有設置 -r,則反斜杠都會被 “吃掉”
# 參考:https://unix.stackexchange.com/questions/18886/why-is-while-ifs-read-used-so-often-instead-of-ifs-while-read/18936#18936
STDOUT
$ echo string
圖片轉換
$ convert original_image.png converted_image.jpg # 圖片格式轉換,支持格式:jpg, png, gif, bmp, tif
$ convert -gravity south \ # 設置 draw text 的位置
-pointsize 36 \ # 設置字體大小
-draw "text 0,10 'Hello world'" original_image.jpg converted.jpg
文件搜索
$ find # 遞歸輸出當前目錄及其下所有文件或子目錄,相當於`find . -print`
$ find dir # 遞歸輸出dir 目錄及其下所有文件或子目錄
$ find dir -type f # 遞歸輸出dir 目錄下的所有文件
$ find dir -type d # 遞歸輸出dir 目錄及其下的所有子目錄
$ find dir -name '*s2_COMP9041' # 遞歸輸出dir 目錄下所有符合通配符 `*s2_COMP9041` 的文件名或目錄名(*此處不匹配斜杠/)
$ find dir -iname '*s2_comp9041'# 遞歸輸出dir 目錄下所有符合通配符 `*s2_comp9041` 的文件名或目錄名(*此處不匹配斜杠/)(case insensitive)
$ find dir -path '*.sh' # 遞歸輸出dir 目錄下所有符合通配符 `*.sh` 的文件路徑或目錄路徑(*此處匹配斜杠/)
$ find dir -ipath '*.SH' # 遞歸輸出dir 目錄下所有符合通配符 `*.sh` 的文件路徑或目錄路徑(*此處匹配斜杠/)(case insensitive)
$ find dir -path '*.sh' \ # <或>操作
-or -path '*.pl' \
-or -path '*.py'
$ find dir -not -name '*.sh' \ # <非>操作
-type f
$ find dir -path '*.tmp' \ # <與>操作
-type f -delete # 遞歸刪除dir 目錄下所有路徑符合通配符 `*.tmp` 的文件
$ find dir -name '*s2_COMP9041'\# 遞歸遍歷dir 目錄下所有
-type d \ # 的目錄名
-prune # 如果目錄名符合通配符 `'*s2_COMP9041'`,該目錄下所有內容都被忽略
-print # 並輸出(該選項可省略)
$ find dir -name '*s2_COMP9041'\# 遞歸遍歷dir 目錄下所有
-type d \ # 的目錄名
-prune # 如果目錄名符合通配符 `'*s2_COMP9041'`,該目錄下所有內容都被忽略
-or -print # 輸出其它未被忽略的目錄及文件
# 有時可能僅僅需要排除目錄,而非連同該目錄下的所有文件。此時需要用到 -depth 選項
$ find dir -depth \ # 規定遍歷順序:遇到目錄時,先列出目錄中的文件,再列出目錄自己
-name '*s2_COMP9041'\# 遞歸遍歷dir 目錄下所有
-type d \ # 的目錄名
-prune # 如果目錄名符合通配符 `'*s2_COMP9041'`,該目錄下所有內容都被忽略
-or -print # 輸出其它未被忽略的目錄及文件
# 參考:https://math2001.github.io/post/bashs-find-command/
條件判斷
#!/bin/bash
# 參數個數檢查
if test $# -ne 2
# 或 if [ $# -ne 2 ]
# 或 if (( $# != 2 ))
then
echo Usage: "$0": '<non-negtive_int> <string>'
exit 1
fi
# 參數類型檢查
if test $1 -ge 0
# 或 if [ $1 -ge 0 ]
then
:
else
echo "$0": argument 1 must be a non-negtive integer!
exit 2
fi
# 程序邏輯開始...
for
Loop
# 遍歷當前目錄中的所有文件名
## Version 1 ## 不包括隱藏文件 ##
$ shopt -u dotglob
$ for filename in *
> do echo $filename
> done
## Version 2 ## 包括隱藏文件 ##
$ shopt -s dotglob
$ for filename in *
> do echo $filename
> done
## 根據 argument 輸入的目錄路徑 `important_files/*` 遍歷其中(包括子目錄)所有的文件
# Input: $ readfile.sh important_files/*
$ for paths in "$@" # 注意! 1.不是$1 2.Add double quotes
> do
> find $paths -type f -print0 |
> while read -d $'\0' path
> do echo $path
> done
> done
# 類似 C語言 的用法
$ begin=0; end=5; step=1
$ for ((i=$begin; ((i < $end)); ((i += $step)) ))
> do echo $i
> done
# write files from arguments by line with line number
line_no=0
for word in "$@"
do
((line_no+=1))
echo $line_no $word
done > filepath
while
Loop
# 類似 C語言 的用法
$ begin=0; end=5; step=1
$ i=$begin
$ while test $i -lt $end <OR> while [ $i -lt $end ] <OR> while (( i < end ))
> do echo $i
> (( i+=step ))
> done
# read files by line
while read line
do
echo $line
done < filepath
sh
$ sh -x your_shell_script.sh # 用於追蹤程序流,debug 時很實用
一些細節
Silence
$ egrep 'regex' filename.txt >/dev/null 2>&1 # >/dev/null —— stdout(1) 被扔到 /dev/null
# >2>&1 —— stderr(2) 跟着 stdout(1) 走
# 總結:不在屏幕上打印 stdout 和 stderr
引號問題,date
用法,圖片處理
# 實際應用:給圖片打tag
$ date_time=`date "+%H:%M %d %b,%Y"`
$ convert -draw "text 0,0 '$date_time'" oringal.jpg tagged.jpg
Linux 文件名相關問題
文件名以 “-” 開頭
$ mv -- filename(以‘-’開頭) newfilename # -- 表示下一個參數不會是 Option(必須是文件名)
文件名中絕對不能包含的字符
['/', '\0']
文件名大小寫敏感
$ touch important_file.db Important_File.Db IMPORTANT_FILE.DB
$ ls
important_file.db Important_File.Db IMPORTANT_FILE.DB