1. 程式人生 > 實用技巧 >bash 跟著敲 基礎部分(適合初學者學習和非初學者參考)

bash 跟著敲 基礎部分(適合初學者學習和非初學者參考)

目錄

  1. 基本操作
    1.1. 檔案操作
    1.2. 文字操作
    1.3. 目錄操作
    1.4. SSH、系統資訊和網路操作
    1.5. 程序監控操作
  2. 基本 shell 程式設計
    2.1. 變數
    2.2 陣列
    2.3. 字串替換
    2.4. 函式
    2.5. 條件語句
    2.6. 迴圈語句
  3. 小技巧
  4. 除錯

1. 基本操作

a. export

輸出所有的環境變數。 如果你想檢視某個特定變數的值,用echo $VARIABLE_NAME

export

示例:

$ export
AWS_HOME=/Users/adnanadnan/.aws
LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LESS=-R

$ echo $AWS_HOME
/Users/adnanadnan/.aws

b. whatis

whatis 顯示某個使用者命令、系統呼叫或庫函式的描述文件,或操作手冊中存在的其他文件。

whatis something

示例:

$ whatis bash
bash (1)             - GNU Bourne-Again SHell

c. whereis

whereis 查詢可執行檔案、原始檔或者說明文件的位置,使用的是一個系統自動構建的資料庫。

whereis name

示例:

$ whereis php
/usr/bin/php

d. which

which 在環境變數 PATH 指定的所有資料夾中查詢可執行檔案的位置。它會打印出可執行檔案的絕對路徑。

which program_name 

示例:

$ which php
/c/xampp/php/php

e. clear

清空視窗中的內容。

1.1. File Operations

cat chmod chown cp diff file find gunzip gzcat gzip head
lpq lpr lprm ls more mv rm tail
touch

a. cat

在 UNIX 和 Linux 中,它有以下幾種用途

  • 把文字檔案顯示在螢幕上
  • 複製文字檔案
  • 合併文字檔案
  • 建立新的文字檔案
cat filename
cat file1 file2 
cat file1 file2 > newcombinedfile
cat < file1 > file2 #copy file1 to file2

b. chmod

chmodchange mod 的意思,它用來改變檔案或資料夾的讀、寫和執行許可權。詳細資訊參見這個連結

chmod -options filename

c. chown

chownchange owner 的意思,它用來改變一個檔案或者資料夾的所有者,所有者可以是一個使用者或一個使用者組。

chown -options user:group filename

d. cp

把一個檔案從一個位置複製到另外一個位置

cp filename1 filename2

上面 filename1 是原始檔位置, filename2 是目標位置(精確到檔名)。

e. diff

比對兩個檔案,輸出他們的差異。

diff filename1 filename2

f. file

檢測檔案型別

file filename

示例:

$ file index.html
 index.html: HTML document, ASCII text

g. find

在某個資料夾中用一定規則查詢檔案

find directory options pattern

示例:

$ find . -name README.md
$ find /home/user1 -name '*.png'

h. gunzip

解壓用 gzip 方法壓縮的檔案

gunzip filename

i. gzcat

在不解壓的情況下,檢視 gzip 壓縮過的檔案

gzcat filename

j. gzip

壓縮檔案

gzip filename

k. head

輸出檔案的前 10 行

head filename

l. lpq

輸出印表機列表

lpq

示例:

$ lpq
Rank    Owner   Job     File(s)                         Total Size
active  adnanad 59      demo                            399360 bytes
1st     adnanad 60      (stdin)                         0 bytes

m. lpr

列印一個檔案

lpr filename

n. lprm

從印表機任務佇列中移除某個任務

lprm jobnumber

o. ls

列出當前資料夾下所有檔案。ls 有很多選項:-l 以詳細資訊格式列出檔案,詳細資訊包括檔案實際大小,檔案所有者,可檢視者,以及最後修改時間。-a 列出所有檔案,包括隱藏檔案。更多資訊參見這個連結

ls option

示例:

$ ls -la
rwxr-xr-x   33 adnan  staff    1122 Mar 27 18:44 .
drwxrwxrwx  60 adnan  staff    2040 Mar 21 15:06 ..
-rw-r--r--@  1 adnan  staff   14340 Mar 23 15:05 .DS_Store
-rw-r--r--   1 adnan  staff     157 Mar 25 18:08 .bumpversion.cfg
-rw-r--r--   1 adnan  staff    6515 Mar 25 18:08 .config.ini
-rw-r--r--   1 adnan  staff    5805 Mar 27 18:44 .config.override.ini
drwxr-xr-x  17 adnan  staff     578 Mar 27 23:36 .git
-rwxr-xr-x   1 adnan  staff    2702 Mar 25 18:08 .gitignore

p. more

輸出一個檔案的第一部分(用空格移動,按 q 退出)

more filename

q. mv

把一個檔案從一個位置移動到另一個位置

mv filename1 filename2

上面filename1 是原始檔的路徑, filename2是目標路徑。(都精確到檔名)

它也可以用來重新命名檔案

mv old_name new_name

r. rm

刪除一個檔案
rm: directory: is a directory
如果想刪除資料夾,需要新增 r 引數,這樣會遞迴的刪除資料夾內所有內容。可以使用 f 引數強制刪除,略過確認環節。

rm filename

s. tail

輸出檔案的最後 10 行。新增-f可以動態輸出檔案新新增的文字。

tail filename

t. touch

更新某個檔案的訪問和修改時間戳,如果檔案不存在,將會被建立。

touch filename

示例:

$ touch trick.md

1.2. 文字操作

awk cut echo egrep fgrep fmt grep nl sed sort
tr uniq wc

a. awk

awk 是文字操作最有用的命令。它按行處理整個檔案,它預設用空格把每一行分隔成很多欄位。最常用的語法是:

awk '/search_pattern/ { action_to_take_if_pattern_matches; }' file_to_parse

/etc/passwd 檔案為例,該檔案包含以下資料:

root:x:0:0:root:/root:/usr/bin/zsh
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync

我們想從這個檔案中過濾出每一行的 username 部分。-F 引數用來指明用來把行內內容分隔的分隔符。這個例子中,我們用:來分隔。{ print $1 } 意思是輸出行內第一個匹配的欄位。

awk -F':' '{ print $1 }' /etc/passwd

執行上面的命令之後,你會得到下面的輸出。

root
daemon
bin
sys
sync

更多詳細資訊,參見這個連結

b. cut

按行從檔案中摘取文字並輸出

example.txt

red riding hood went to the park to play

用空格分隔每一行,並輸出第2,7,9列

cut -d " " -f2,7,9 example.txt
riding park play

c. echo

輸出命令之後的文字到標準輸出或檔案

輸出 "Hello World"

echo Hello World
Hello World

輸出 "Hello World",單詞間用換行符分隔

echo -ne "Hello\nWorld\n"
Hello
World

d. egrep

輸出檔案中匹配指定模式的行,是 grep 命令的擴充套件模式,支援更多正則表示式(等同於 grep -E)。

example.txt

Lorem ipsum
dolor sit amet, 
consetetur
sadipscing elitr,
sed diam nonumy
eirmod tempor
invidunt ut labore
et dolore magna
aliquyam erat, sed
diam voluptua. At
vero eos et
accusam et justo
duo dolores et ea
rebum. Stet clita
kasd gubergren,
no sea takimata
sanctus est Lorem
ipsum dolor sit
amet.

輸出包含 Lorem 或 dolor 的行

egrep '(Lorem|dolor)' example.txt
or
grep -E '(Lorem|dolor)' example.txt
Lorem ipsum
dolor sit amet,
et dolore magna
duo dolores et ea
sanctus est Lorem
ipsum dolor sit

e. fgrep

輸出檔案中包含給定字串的行,指定的模式將不被認做正則,而是字串。(等同於:grep -F

example.txt

Lorem ipsum
dolor sit amet,
consetetur
sadipscing elitr,
sed diam nonumy
eirmod tempor
foo (Lorem|dolor) 
invidunt ut labore
et dolore magna
aliquyam erat, sed
diam voluptua. At
vero eos et
accusam et justo
duo dolores et ea
rebum. Stet clita
kasd gubergren,
no sea takimata
sanctus est Lorem
ipsum dolor sit
amet.
  • 輸出在 example.txt 中包含字串 (Lorem|dolor) 的所有行*
fgrep '(Lorem|dolor)' example.txt
or
grep -F '(Lorem|dolor)' example.txt
foo (Lorem|dolor) 

f. fmt

簡單的文字格式化工具

example: example.txt (1 行)

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

把 example.txt 格式化為 20 個字元的寬度

cat example.txt | fmt -w 20
Lorem ipsum
dolor sit amet,
consetetur
sadipscing elitr,
sed diam nonumy
eirmod tempor
invidunt ut labore
et dolore magna
aliquyam erat, sed
diam voluptua. At
vero eos et
accusam et justo
duo dolores et ea
rebum. Stet clita
kasd gubergren,
no sea takimata
sanctus est Lorem
ipsum dolor sit
amet.

g. grep

在檔案中查詢文字。你可以用 grep 去查詢匹配一個或多個正則表示式的文字行,然後輸出這些行。

grep pattern  filename

示例:

$ grep admin /etc/passwd
_kadmin_admin:*:218:-2:Kerberos Admin Service:/var/empty:/usr/bin/false
_kadmin_changepw:*:219:-2:Kerberos Change Password Service:/var/empty:/usr/bin/false
_krb_kadmin:*:231:-2:Open Directory Kerberos Admin Service:/var/empty:/usr/bin/false

你也可以通過 -i 引數強制忽略大小寫。引數-r則被用來遞迴地查詢指定資料夾下的所有檔案,例如:

$ grep -r admin /etc/

引數 -w 表示只查詢單詞。關於 grep的更多資訊,參見這個連結

h. nl

給檔案新增行號並輸出

example.txt

Lorem ipsum
dolor sit amet,
consetetur
sadipscing elitr,
sed diam nonumy
eirmod tempor
invidunt ut labore
et dolore magna
aliquyam erat, sed
diam voluptua. At
vero eos et
accusam et justo
duo dolores et ea
rebum. Stet clita
kasd gubergren,
no sea takimata
sanctus est Lorem
ipsum dolor sit
amet.

給 example.txt 中的內容新增行號並輸出

nl -s". " example.txt 
     1. Lorem ipsum
     2. dolor sit amet,
     3. consetetur
     4. sadipscing elitr,
     5. sed diam nonumy
     6. eirmod tempor
     7. invidunt ut labore
     8. et dolore magna
     9. aliquyam erat, sed
    10. diam voluptua. At
    11. vero eos et
    12. accusam et justo
    13. duo dolores et ea
    14. rebum. Stet clita
    15. kasd gubergren,
    16. no sea takimata
    17. sanctus est Lorem
    18. ipsum dolor sit
    19. amet.

i. sed

用於過濾和替換文字的流式編輯命令

example.txt

Hello This is a Test 1 2 3 4

把 example.txt 所有空格替換為連字元並輸出

sed 's/ /-/g' example.txt
Hello-This-is-a-Test-1-2-3-4

把所有數字替換為 "d"

sed 's/[0-9]/d/g' example.txt
Hello This is a Test d d d d

j. sort

對檔案中的行進行排序

example.txt

f
b
c
g
a
e
d

對 example.txt 中的行進行排序

sort example.txt
a
b
c
d
e
f
g

隨機打亂已經排好序的 example.txt(測試出現問題)// todo

sort example.txt | sort -R
b
f
a
c
d
g
e

k. tr

轉換或刪除字元

example.txt

Hello World Foo Bar Baz!

把所有小寫字母轉換成大寫字母

cat example.txt | tr 'a-z' 'A-Z' 
HELLO WORLD FOO BAR BAZ!

把所有的空格都轉換為換行符

cat example.txt | tr ' ' '\n'
Hello
World
Foo
Bar
Baz!

l. uniq

統計或精簡重複的行

example.txt

a
a
b
a
b
c
d
c

輸出 example.txt 中所有不重複的行(需要先進行排序, 否則相同行中間的行會被忽略)

sort example.txt | uniq
a
b
c
d

輸出去重後的所有行,並顯示不重複行中每一行在原檔案中的重複次數

sort example.txt | uniq -c
    3 a
    2 b
    2 c
    1 d

m. wc

輸出檔案中的行、單詞、字元個數。

wc filename

示例:

$ wc demo.txt
7459   15915  398400 demo.txt

demo.txt中有 7459 行, 15915 個單詞以及 398400 個字元.

1.3. Directory Operations

cd mkdir pwd

a. cd

進入某個檔案目錄,執行:

$ cd

會進入 home 目錄。這個命令接受一個可選的目錄名稱的引數,指示要進入的目錄。

cd dirname

b. mkdir

建立一個新資料夾

mkdir dirname

c. pwd

顯示當前所在的檔案目錄(絕對路徑)

pwd

1.4. SSH, System Info & Network Operations

bg cal date df dig du fg finger jobs last
man passwd ping ps quota scp ssh top uname uptime
w wget whoami whois

a. bg

列出所有被停止或後臺執行的任務,或將一個已停止的任務後臺執行。

b. cal

輸出當前月份的日曆

c. date

輸出當前日期和時間

d. df

輸出磁碟使用統計資料

e. dig

輸出某個域名的 DNS 資訊

dig domain

f. du

輸出某些檔案或目錄的硬碟使用情況。更多詳細資訊參見這個連結

du [option] [filename|directory]

Options:

  • -h (人類可讀) 把結果以 KB、 MB 、GB 為單位輸出。
  • -s (壓縮總結) 輸出一個目錄總的磁碟空間佔用情況,總結輸出子目錄的報告。

示例:

du -sh pictures
1.4M pictures

g. fg

輸出前臺中最近執行的任務

h. finger

輸出某個使用者的資訊

finger username

i. jobs

列出在後臺執行的任務,同時給出任務號

j. last

列出特定使用者的登入記錄

last yourUsername

k. man

輸出特定命令的使用手冊

man command

l. passwd

讓當前登入的使用者更改他的密碼

m. ping

ping 某個主機然後輸出結果

ping host

n. ps

列出某個使用者的所有程序

ps -u yourusername

o. quota

顯示磁碟使用量和配額

quota -v

p. scp

在本地主機和遠端主機之間或兩個遠端主機之間傳輸檔案

從本地主機複製檔案到遠端主機

scp source_file user@host:directory/target_file

從遠端主機複製檔案到本地主機

scp user@host:directory/source_file target_file
scp -r user@host:directory/source_folder target_folder

這個命令也接受一個引數 -P,用來連線指定埠

scp -P port user@host:directory/source_file target_file

q. ssh

ssh(SSH 客戶端)是一個用來登入到遠端主機並執行命令的程式

ssh user@host

這個命令也接受一個可選引數 -p,用來指定連線到特定的埠。

ssh -p port user@host

r. top

動態展示所有活躍的程序

s. uname

輸出核心資訊

uname -a

t. uptime

輸出伺服器運行了多長時間以及有多少個使用者登入

u. w

輸出系統線上使用者

v. wget

下載檔案

wget file

w. whoami

輸出現在登入的使用者的使用者名稱

x. whois

獲取某個域名的 whois 資訊

whois domain

1.5. Process Monitoring Operations

kill killall & nohup

a. kill

結束指定 PID 代表的程序

kill PID

b. killall

結束某個名字代表的所有程序

killall processname

c. &

使得 & 之前的命令作為後臺程序執行在 subshell 中

command &

d. nohup

nohup 代表 No Hang Up,也即不要掛起。這條命令允許其它命令、程序或shell指令碼在你退出shell之後繼續在後臺執行

nohup command

把它和 & 結合使用可以建立後臺程序

nohup command &

2. Basic Shell Programming

在 bash 指令碼檔案中的第一行被叫做 shebang。這一行決定了指令碼可以像一個獨立的可執行檔案一樣執行,而不用在終端之前輸入sh,bash,python,php等。

#!/bin/bash

2.1. Variables

在 bash 中建立變數跟其它語言相似。沒有變數型別,bash 中的變數可以儲存一個數字、一個字元、一個字串等等。同時無需提前宣告變數,給變數賦值會直接建立變數。

示例:

str="hello world"

上面一行建立了一個變數 str 然後把 "hello world" 賦值給它。通過在變數名之前新增$符號,可以取到變數裡面儲存的值。

示例:

echo $str   # hello world

2.2. Array

像其它語言一樣,bash 也有陣列型別。bash 中的陣列是一個儲存著很多值的變數,陣列的長度沒有限制,下標也是從 0 開始。在 bash 中有好幾種方法建立一個數組,如下所示。

Examples:

array[0] = val
array[1] = val
array[2] = val
array=([2]=val [0]=val [1]=val)
array=(val val val)

使用如下語法獲得陣列特定位置的值:

${array[i]}     # i是陣列下標

如果沒有指定陣列下標,預設返回第一個元素。想知道陣列中有多少個元素,使用下面的語法:

${#array[@]}

Bash 也支援三元運算子,如下面的例子所示:

${varname:-word}    # 如果 varname 存在而且不為 null,返回它的值,否則返回 word
${varname:=word}    # 如果 varname 存在而且不為 null,返回它的值,否則把word賦值給它並且返回 word
${varname:+word}    # 如果 varname 存在而且不為 null,返回 word,否則返回 null
${varname:offset:length}    # 它返回 $varname 的子字串,從 offset 處開始,長度為 length

2.3 String Substitution

通過下面的語法來學習字串相關操作

${variable#pattern}         # 如果 pattern 匹配變數值的起始部分,刪除匹配 pattern 的最短的部分,然後返回剩餘的
${variable##pattern}        # 如果 pattern 匹配變數值的起始部分,刪除匹配 pattern 的最長的部分,然後返回剩餘的
${variable%pattern}         # 如果 pattern 匹配變數值的結束部分,刪除匹配 pattern 的最短的部分,然後返回剩餘的
${variable%%pattern}        # 如果 pattern 匹配變數值的結束部分,刪除匹配 pattern 的最長的部分,然後返回剩餘的
${variable/pattern/string}  # 把變數值中匹配 pattern 的最長的部分替換為 string,只替換第一個匹配的部分
${variable//pattern/string} # 把變數值中匹配 pattern 的最長的部分替換為 string,全域性進行替換
${#varname}     # 返回變數值作為一個字串的長度

2.4. Functions

As in almost any programming language, you can use functions to group pieces of code in a more logical way or practice the divine art of recursion. Declaring a function is just a matter of writing . Calling a function is just like calling another program, you just write its name.
就像在其它程式語言中那樣,您可以使用 function 來以更合乎邏輯的方式聚合程式碼,或實現遞迴的神聖藝術。宣告一個 function 只需要寫下function my_func { my_code } ,呼叫 function 就像呼叫另外的程式一樣,使用方法名稱即可。

function name() {
    shell commands
}

示例:

#!/bin/bash
function hello {
   echo world!
}
hello

function say {
    echo $1
}
say "hello world!"

當你執行上面例子中的 hello 方法時,它會輸出 "world!"。上面的兩個方法 hellosay 一模一樣的, say 有一些不同,這個方法會打印出它接受到的第一個引數。方法中的引數,跟指令碼語言中的處理方式一樣。

2.5. Conditionals

bash 中的條件語句跟其他程式語言類似。條件語句有很多種形式,就像最常見的基本形式是 if 表示式 then 語句,代表如果表示式為真,則執行響應的語句。

if [expression]; then
    will execute only if expression is true
else
    will execute if expression is false
fi

有些時候如果條件語句變得太複雜,你可以用 case statements 來完成相同的條件判斷功能。

case expression in
    pattern1 )
        statements ;;
    pattern2 )
        statements ;;
    ...
esac

Expression Examples:

statement1 && statement2  # 兩個語句都為真
statement1 || statement2  # 至少一個語句為真

str1=str2       # str1 匹配 str2
str1!=str2      # str1 不匹配 str2
str1<str2       # str1 小於 str2
str1>str2       # str1 大於 str2
-n str1         # str1 不是 null (長度大於 0)
-z str1         # str1 是 null (長度為 0)

-a file         # 檔案存在
-d file         # 檔案存在而且是目錄
-e file         # 檔案存在,跟 -a 一樣
-f file         # 檔案存在,而且是常規檔案(不是目錄或者其他特殊型別的檔案)
-r file         # 你有讀許可權
-s file         # 檔案存在而且不為空
-w file         # 你有寫許可權
-x file         # 你對檔案有執行許可權,如果 file 是目錄的話,你對它有搜尋許可權
-N file         # 從上次讀之後檔案被修改過
-O file         # 你是檔案所有者
-G file         # 檔案的 group ID 跟你的 group ID (或之一,如果你在很多分組裡)相同

file1 -nt file2     # file1 比 file2 更新
file1 -ot file2     # file1 比 file2 更老

-lt     # 小於
-le     # 小於等於
-eq     # 等於
-ge     # 大於等於
-gt     # 大於
-ne     # 不等於

2.6. Loops

bash 中有三種類型的迴圈。for, whileuntil

不同的 for 語法:

for x := 1 to 10 do
begin
  statements
end

for name [in list]
do
  statements that can use $name
done

for (( initialisation ; ending condition ; update ))
do
  statements...
done

while 語法:

while condition; do
  statements
done

until 語法:

until condition; do
  statements
done

3. Tricks

設定別名

執行 nano ~/.bash_profile 來開啟 bash_profile

alias dockerlogin='ssh [email protected] -p2222' # 在 .bash_profile 中設定別名

快速進入某個目錄

nano ~/.bashrc

export hotellogs="/workspace/hotel-api/storage/logs"

source ~/.bashrc
cd $hotellogs

跳出陷阱

通過執行清理語句使得你的指令碼更有魯棒性

function finish {
  # 在這裡執行清理語句,例如,殺掉所有 fork 的程序。
  jobs -p | xargs kill
}
trap finish EXIT

儲存環境變數

當你在 shell 中執行 export FOO = BAR, 環境變數只在當前 shell 和它的子 shell 中存在,如果想在將來能夠永久使用這個環境變數,只需要在 ~/.bash_profile 檔案後面新增要執行的命令即可。

echo export FOO=BAR >> ~/.bash_profile

訪問你的指令碼

通過在 home 目錄下建立 bin 資料夾, 你可以很容易的訪問你的指令碼,mkdir ~/bin 之後,在 bin 目錄裡面的所有指令碼都能在任何別的目錄下訪問到。

如果還是不能訪問,把下面的程式碼新增到 ~/.bash_profile 檔案中,然後執行source ~/.bash_profile

    # 如果使用者的私有 bin 目錄存在的話,把它新增到 PATH 變數中
    if [ -d "$HOME/bin" ] ; then
        PATH="$HOME/bin:$PATH"
    fi

4. 除錯

你可以很容易地通過傳遞不同的引數給 bash 命令來除錯指令碼。例如, -n 將會只檢查指令碼的語法錯誤而不執行指令碼。 -v 將會在命令執行前輸出它們。 -x 將會在命令列處理之後輸出命令。

bash -n scriptname
bash -v scriptname
bash -x scriptname

貢獻

  • 報告問題 How to
  • 提交改進型的合併請求 How to
  • 幫助傳播

Translation

License