日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux基础:Shell脚本学习

發布時間:2025/4/16 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux基础:Shell脚本学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、shell簡介

Shell是用戶和Unix/Linux內核溝通的橋梁,用戶的大部分工作都是通過Shell完成的。Shell既是一種命令語言,又是一種程序設計語言。作為命令語言,它交互式地解釋和執行用戶輸入的命令;作為程序設計語言,它定義了各種變量和參數,并提供了許多在高級語言中才具有的控制結構,包括循環和分支。

? ? 它雖然不是Unix/Linux系統內核的一部分,但它調用了系統核心的大部分功能來執行程序、建立文件并以并行的方式協調各個程序的運行。因此,對于用戶來說,shell是最重要的實用程序,深入了解和熟練掌握shell的特性極其使用方法,是用好Unix/Linux系統的關鍵。

????Shell 腳本: 其實就是命令的堆積。

Shell有兩種執行命令的方式

  • 交互式(Interactive):解釋執行用戶的命令,用戶輸入一條命令,Shell就解釋執行一條。

  • 批處理(Batch):用戶事先寫一個Shell腳本(Script),其中有很多條命令,讓Shell一次把這些命令執行完,而不必一條一條地敲命令。

? ? shell只定義了一個非常簡單的編程語言,所以,如果你的腳本程序復雜度較高,或者要操作的數據結構比較復雜,那么還是應該使用Python、Perl這樣的腳本語言,或者是你本來就已經很擅長的高級語言。因為sh和bash在這方面很弱,比如說:

  • 它的函數只能返回字串,無法返回數組

  • 它不支持面向對象,你無法實現一些優雅的設計模式

  • 它是解釋型的,一邊解釋一邊執行,連PHP那種預編譯都不是,如果你的腳本包含錯誤(例如調用了不存在的函數),只要沒執行到這一行,就不會報錯

二、第一個shell腳本

? ? Shell腳本典型的開發周期:直接在命令行(command line)上測試。然后,一旦找到能夠完成工作的適當語法,再將它們放進一個獨立的腳本里,并為該腳本設置執行的權限。

1、編寫

? ? 打開文本編輯器,新建一個文件,擴展名最好為sh(sh代表shell),雖然擴展名并不影響腳本執行,但是便于我們識別,而且對于編輯器來說,還可能進行語法高亮。

#!/bin/bash#?print?the?"hello?world" echo?"Hello?World"

2、執行

運行Shell腳本有兩種方法:

  • 作為可執行程序

chmod?+x?./first.sh??????#?使腳本具有執行權限 ./first.sh???????????????#?執行腳本

注意:一定是 ./first.sh。為什么呢?通常我們在執行命令的時候,shell會根據PATH變量定義的路徑進行查找,而我們的當前路徑一般不會加入PATH變量,所以就會提示?-bash: first.sh : command not found。

./first.sh ?是通過相對路徑,指明執行 當前目錄下的叫做 first.sh 的文件。

  • 作為解釋器參數

/bin/bash??first.sh

?3、運行原理

? ? 當shell執行一個程序時,會要求UNIX內核啟動一個新的進程(process),以便在該進程里執行所指定的程序。內核知道如何為“編譯型”程序做這件事。shell腳本并非編譯型程序;當shell要求內核執行它時,內核將無法做這件事,并回應“not executable format file”錯誤信息。shell收到此錯誤信息時,就會認為“這不是編譯型程序,那么一定是shell腳本”,”退回到shell”接著會啟動一個新的/bin/sh 副本來執行該程序。

? ? 當系統只有一個shell時,“退回到/bin/sh”的機制非常方便。但現行的系統都會擁有好幾個shell,因此需要通過一種方式,告知內核應該以哪個shell來執行所指定的shell腳本。事實上,這么做有助于執行機制的通用化,讓用戶得以直接引用任何的程序語言解釋器,而非只是一個命令shell。方法是,通過腳本文件特殊的第一行來設置:在第一行的開頭處使用 #!這兩個字符(必須:頂行&&頂頭)。


????在計算機科學中,sha-bang是一個由井號和嘆號構成的字符串行(#!),其出現在文本文件的第一行最前兩個字符。 在文件中存在sha-bang的情況下,類Unix操作系統的程序載入器會分析sha-bang后的內容,將這些內容作為解釋器指令,并調用該指令,并將載有sha-bang的文件路徑作為該解釋器的參數[1]。#! (magic number)為了讓Linux內核識別這是什么格式的文件。

* * *

????The sha-bang ( #!) ?at the head of a script tells your system that this file is a set of commands to be fed to the command interpreter indicated. The #! is actually a two-byte magic number, a special marker that designates a file type, or in this case an executable shell script (type man magic for more details on this fascinating topic). Immediately following the sha-bang is a path name. This is the path to the program that interprets the commands in the script, whether it be a shell, a programming language, or a utility. This command interpreter then executes the commands in the script, starting at the top (the line following the sha-bang line), and ignoring comments.?

#!/bin/sh #!/bin/bash #!/usr/bin/perl #!/usr/bin/tcl #!/bin/sed?-f #!/bin/awk?-f

????Each of the above script header lines calls a different command interpreter, be it /bin/sh, the default shell (bash in a Linux system) or otherwise. Using #!/bin/sh, the default Bourne shell in most commercial variants of UNIX, makes the script portable to non-Linux machines, though you sacrifice Bash-specific features. The script will, however, conform to the POSIX ?sh standard.

Note that the path given at the "sha-bang" must be correct, otherwise an error message -- usually "Command not found." -- will be the only result of running the script.?

#! can be omitted if the script consists only of a set of generic system commands, using no internal shell directives. The second example, above, requires the initial #!, since the variable assignment line, lines=50, uses a shell-specific construct. Note again that #!/bin/sh invokes the default shell interpreter, which defaults to /bin/bash on a Linux machine.

? This tutorial encourages a modular approach to constructing a script. Make note of and collect "boilerplate" code snippets that might be useful in future scripts. Eventually you will build quite an extensive library of nifty routines. As an example, the following script prolog tests whether the script has been invoked with the correct number of parameters.


When you execute a program, the kernel checks whether it starts by some magic byte sequence. If the executable file starts with #!, the kernel interprets the rest of the line as an interpreter name.?

????If the executable file starts with \177ELF (where \177 is byte 127), it loads the file as an ELF executable; that's the normal kind on most unix systems nowadays.

????If the kernel doesn't recognize the file format, it refuses to execute the file and returns the error ENOEXEC (Exec format error). When the shell notices that, it takes upon itself to execute the program as a shell script. If the magic line is not provided, a default shell is used to run the script. This default shell could either be Bourne shell (sh) which is the case in some flavors, however, in some other flavors, the default shell used is same as login shell to execute it. The thing is: Don't leave it to the system to decide the shell, always provide the shell which you want in the first line.

[root@skype?~]#?file?/etc/init.d/sshd /etc/init.d/sshd:?Bourne-Again?shell?script?text?executable [root@skype?~]#?file?/bin/ls /bin/ls:?ELF?64-bit?LSB?executable,?x86-64,?version?1?(SYSV),?dynamically?linked?(uses?shared?libs),?for?GNU/Linux?2.6.18,?stripped


Q. Sha-Bang(#!)的編寫有什么規范?

A. Sha-Bang(#!)應該位于腳本的第一行,并且頂格填寫,否則都是錯的,即使Sha-Bang之前的內容都是注釋,這種錯誤是常見的,而且不易發現的,因為此時Sha-Bang(#!)所在行實際上是不起效的,系統使用了默認的命令行解釋器


Q. 為什么推薦這種寫法:#!/bin/env perl?

A. 因為這是有利于移植腳本到其它平臺的寫法,解釋器的默認安裝路徑在各個操作系統是不太一樣的,有的是/bin/,有的是/usr/bin/,甚至有可能是用戶自定義的路徑,使用env就基本上能夠通用了。雖然env也有可能在/bin/或者/usr/bin/中,但通常的情況是在這兩個路徑下都有env,或者其中一個是另一個的符號鏈接


????用戶可以指定命令解釋器,而非只是一個命令shell。通過腳本文件中特殊的第一行來設置:在第一行的開頭處使用 #! 這兩個字符。當一個文件的開頭字符是 #! 時,內核會掃描該行的其余部分,看是否存在可用來執行程序的解釋器的完整路徑。(中間如果出現任何空白符號都會略過),此外,內核還會掃描是否有一個選項(有且只能有一個)要傳遞給解釋器,內核會以被指定的選項來引用解釋器。

#! /bin/csh –f ? ? ? ??

#! /bin/awk –f (直接通過內核調用awk程序解釋后面的腳本,而不是shell間接調用)

假設有一個awk腳本,/usr/test.awk,它的第一行如下: #! /bin/awk –f,如果shell的查找路徑(PATH)中有 /usr,當用戶鍵入 test.awk時,內核解釋 #! 這行后,便會以如下的方式來引用awk:

? ? ? ? ?/bin/awk–f ?/usr/test.awk

這樣的機制讓我們得以輕松地引用任何的解釋器。

?

4、注釋

以”#“開頭的行都是注釋,會被解釋器忽略。

5、輸出


????echo命令將參數打印到標準輸出(把字符串轉換為數據流),參數之間以一個空格隔開,并以換行符號結尾。-n選項會省略結尾的換行符。` ` 或者 $()命令則把數據流轉換為字符串。


????printf 命令模仿C程序庫里的printf()庫函數。它幾乎復制了其所有功能。完整的語法分為兩部分: printf ?“format-string” ?[argumnets …]

參數以空白符分隔,如果參數的個數比格式聲明的多,則printf會循環且依次的使用格式字符串里的格式聲明,直到處理完參數。意味著把參數依次左移處理。這是和C printf函數最大的不同。

三、條件判斷

????很多時候,我們都需要進行條件判斷,然后對不同的結果產生不同的行為。比如判斷 3 是否 大于 2,我們可能想當然像下面這樣,在命令行上:

[root@skype?tmp]#?3?>?2 -bash:?3:?command?not?found [root@skype?tmp]#?ls 2

很遺憾,在命令行上,不能直接這樣測試,因為對于 shell 來說, > , < 都是元(meta)字符,具有特殊含義(重定向)。

????為了解決這種尷尬,于是shell專門提供了關于測試的命令: test, [ , ` `, 可以針對 數字、字符串、文件進行測試。可以man bash得到更多的信息,在里面找到對CONDITIONAL EXPRESSIONS的描述。

test 與 [ ?同樣用于條件測試:?"["是一個可執行程序,路徑是"/usr/bin/[", [ 是一個命令,它是內置命令test的簡寫形式,只不過它要求最后一個參數必須是 ]在使用[ ] 進行判定的時候有一個事項要注意的是,在括號兩邊以及符號兩邊均要有空格。

運算符????????????描述??????????????示例 ##?文件狀態測試 -e?filename?????如果filename?存在,則為真???????[?-e?/var/log/syslog?] -d?filename?????如果filename?為目錄,則為真??????[?-d?/tmp/mydir?] -f?filename?????如果filename?為常規文件,則為真????[?-f?/usr/bin/grep?] -L?filename?????如果filename?為符號鏈接,則為真????[?-L?/usr/bin/grep?] -r?filename?????如果filename?可讀,則為真???????[?-r?/var/log/syslog?] -w?filename?????如果filename?可寫,則為真???????[?-w?/var/mytmp.txt?] -x?filename?????如果filename?可執行,則為真??????[?-L?/usr/bin/grep?] filename1?-nt?filename2??如果?filename1?比?filename2?新,則為真?[?/tmp/install/etc/services-nt?/etc/services?] filename1?-otfilename2???如果filename1?比filename2?舊,則為真??[/boot/bzImage?-ot?arch/i386/boot/bzImage?]##?字符串測試?(請注意引號的使用,這是防止空格擾亂代碼的好方法) -z?string????????如果?string?長度為零,則為真?????[?-z?$myvar?] -n?string????????如果?string?長度非零,則為真?????[-n?$myvar?] string1?=?string2???如果?string1?與?string2?相同,則為真?[$myvar?=?one?two?three?] string1?!=?string2???如果?string1?與?string2?不同,則為真????[$myvar?!=?one?two?three?] string1?<?string2???????如果string1在本地的字典序列中排在string2之前,則為真?????[[$myvar?<?"one"?]] string1?>?string2???????如果string1在本地的字典序列中排在string2之后,則為真?????[[$myvar?>?"one"?]]##?算術測試 num1?-eq?num2?????????????等于???????[?3?-eq?$mynum?] num1?-ne?num2?????????????不等于??????[?3?-ne?$mynum?] num1?-lt?num2?????????????小于???????[?3?-lt?$mynum?] num1?-le?num2?????????????小于或等于????[?3?-le?$mynum?] num1?-gt?num2?????????????大于???????[?3?-gt?$mynum?] num1?-ge?num2?????????????大于或等于????[?3?-ge?$mynum?]


bash?[?] 單雙括號

基本要素:

??[ ] 兩個符號左右都要有空格分隔

??內部操作符與操作變量之間要有空格:如? [ ?“a” ?= ?“b” ?]

??字符串比較中,>?< 需要寫成\> \< 進行轉義

??[ ] 中字符串或者${}變量盡量使用"" 雙引號擴住,避免值未定義引用而出錯的好辦法

??[ ] 中可以使用 –a –o 進行邏輯運算

??[ ] 是bash 內置命令:[ is a shell builtin

bash? [[? ]] 雙方括號

基本要素:

??` ` 兩個符號左右都要有空格分隔

??內部操作符與操作變量之間要有空格:如? [[ ?“a”?= ?“b” ?]]

??字符串比較中,可以直接使用 >?< 無需轉義

??` ` 中字符串或者${}變量盡量如未使用"" 雙引號擴住的話,會進行模式和元字符匹配

??[[] ] 內部可以使用 && ?|| 進行邏輯運算

??` ` 是bash ?keyword:[[ is a shell keyword

` `?其他用法都和[ ]?一樣


[[ ?]]?比[ ]?具備的優勢


? ?①[[是 bash 程序語言的關鍵字。并不是一個命令,` ` 結構比[ ]結構更加通用。在[[和]]之間所有的字符都不會發生文件名擴展或者單詞分割,但是會發生參數擴展和命令替換。

??? ②支持字符串的模式匹配,使用=~操作符時甚至支持shell的正則表達式。字符串比較時可以把右邊的作為一個模式,而不僅僅是一個字符串,比如[[ hello == hell? ]],結果為真。` ` 中匹配字符串或通配符,不需要引號。 ?

??? ③使用` `.``.``.` `條件判斷結構,而不是[... ],能夠防止腳本中的許多邏輯錯誤。比如,&&、||、<和> 操作符能夠正常存在于` `條件判斷結構中,但是如果出現在[ ]結構中的話,會報錯。 ?

??? ④bash把雙中括號中的表達式看作一個單獨的元素,并返回一個退出狀態碼。

? ? ? ?使用` `.``.``.` `條件判斷結構, 而不是[ ... ], 能夠防止腳本中的許多邏輯錯誤. 比如,&&, ||, <, 和> 操作符能夠正常存在于[[]]條件判斷結構中, 但是如果出現在[ ]結構中的話, 會報錯。


注意事項:

因為Bash變量不是強類型的,所以你應該小心:#!/bin/basha=4 b=5#??Here?"a"?and?"b"?can?be?treated?either?as?integers?or?strings. #??There?is?some?blurring?between?the?arithmetic?and?string?comparisons, #+?since?Bash?variables?are?not?strongly?typed.#??Bash?permits?integer?operations?and?comparisons?on?variables #+?whose?value?consists?of?all-integer?characters. #??Caution?advised,?however.echoif?[?"$a"?-ne?"$b"?] thenecho?"$a?is?not?equal?to?$b"echo?"(arithmetic?comparison)" fiechoif?[?"$a"?!=?"$b"?] thenecho?"$a?is?not?equal?to?$b."echo?"(string?comparison)"#?????"4"??!=?"5"#?ASCII?52?!=?ASCII?53 fi#?In?this?particular?instance,?both?"-ne"?and?"!="?work.echoexit?0

????As S.C. points out, in a compound test, even quoting the string variable might not suffice.?[ -n "$string" -o "$a" = "$b" ]?may cause an error with some versions of Bash if?$string?is empty. The safe way is to append an extra character to possibly empty variables,?[ "x$string" != x -o "x$a" = "x$b" ]?(the?"x's"?cancel out).


????各位想過一個問題沒有,為什么能夠進行測試呢?是根據什么來進行判斷的呢?比如 if 語句:

????當我們執行命令后,通常會返回2類值:狀態返回碼(exit status),以及命令執行返回結果:標準輸出或標準錯誤輸出。測試命令是根據 ?exit status 進行判斷的,和 標準輸出的信息沒有半毛錢關系。

寫了一個很2B的程序:

結果無論怎么執行,都是執行的 else 部分。單獨執行每個命令,如下

修改如下即可:

?所以:Shell腳本典型的開發周期:直接在命令行(command line)上測試。然后,一旦找到能夠完成工作的適當語法,再將它們放進一個獨立的腳本里,并為該腳本設置執行的權限。

四、算術運算

大家可以參考:http://mingxinglai.com/cn/2013/01/different-ways-of-doing-arithmetic-operators-in-linux/

6種算術運算方法是:

  • let operation

  • expr operation

  • $[ operation ]

  • $(( operation ))

  • 用 awk 做算術運算(算術擴展)

  • echo "operation" | bc

  • 前面4種shell 腳本進行算術運算的方法, $(()) 最為常用,可以像 C語言 一樣流暢的寫表達式,所有變量可以不加入:“$”符號前綴。(()) 進行運算, $(()) 取出運算結果。有了它,我們就可以拋棄: let, expr 命令了。

    a=$((a+1,?b++,?--c)); echo?$a,$b,$c

    但是它們都有一個致命的缺陷,都不支持浮點數Bash僅支持整數運算(直接把小數部分截斷(Truncate))。

    [root@skype?~]#?echo?$((10?/?3)) 3 [root@skype?~]#?echo?$((10.3?/?3)) -bash:?10.3?/?3:?syntax?error:?invalid?arithmetic?operator?(error?token?is?".3?/?3")

    這里有一個奇怪的現象:

    [root@skype?~]#?echo?$((10.3?/?3))?&>?/dev/null -bash:?10.3?/?3:?syntax?error:?invalid?arithmetic?operator?(error?token?is?".3?/?3")

    為什么無法進行重定向呢? 因為重定向是 shell把其他進程的輸入輸出進行重定向。 而這個錯誤是 bash本身的致命錯誤,所以當然無法重定向咯。


    扯遠了,那么此時我們可以通過 bc, awk 來進行更復雜的運算或浮點運算。

    bc 交互模式:

    [root@skype?~]#?bc bc?1.06.95 Copyright?1991-1994,?1997,?1998,?2000,?2004,?2006?Free?Software?Foundation,?Inc. This?is?free?software?with?ABSOLUTELY?NO?WARRANTY. For?details?type?`warranty'. 10?/?3????????????#?未指定精度默認保留整數 3 scale?=?6?????????#?指定精度 10?/?3 3.333333 quit??????????????#?退出交互模式 [root@skype?~]#

    bc非交互式:

    直接把算術表達式送給bc即可,如果要指定精度,加上scale=N; 用分號隔開

    #?+,?-,?*,?/?,?^ [root@skype?~]#?echo?'scale?=?2;?9?+?8?*?2?-?6?/?5?+?2^3'?|?bc 31.80#?functions [root@skype?~]#?echo?'scale?=?2;?sqrt(15)'?|?bc 3.87#?進制轉換 [root@skype?~]#?echo?'ibase=16;?obase?=?2;?8'?|?bc 1000

    五、流程控制

    ===== for?var?in?item1?item2?...?itemN docommand1command2...commandN done #?把?var分別賦值,?var=item1,?var=item2,?...var=itemN===== for?file?in?* #???????????^??Bash?performs?filename?expansion #+?????????????on?expressions?that?globbing?recognizes.===== #?Missing?in?[list]?in?a?for?loop for?a doecho?-n?"$a?" done#??The?'in?list'?missing,?therefore?the?loop?operates?on?'$@' #+?(command-line?argument?list,?including?whitespace).====== for?((?EXP1;?EXP2;?EXP3?)) docommand1command2command3 done===== while?condition docommand done===== until?condition docommand done======== case?"$variable"?in?"$condition1")?command...?;;?"$condition2")?command...?;;?esac#?僅僅是匹配,而沒有賦值操作#?支持文件名?通配 "E"?|?"e"?)*?) [[:upper:]]???)?echo?"Uppercase?letter";; [0-9]?????????)?echo?"Digit";; [a-zA-Z]*)?return?$SUCCESS;;??#?Begins?with?a?letter?


    轉載于:https://blog.51cto.com/skypegnu1/1624464

    總結

    以上是生活随笔為你收集整理的Linux基础:Shell脚本学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。