Shell 常用命令、基本用法總結


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM