Script Shell - 如果滿足兩個條件如何列印出 echo? (僅限數字,僅滿足2個條件)

Script Shell - 如果滿足兩個條件如何列印出 echo? (僅限數字,僅滿足2個條件)

我是 shell 腳本新手,正在嘗試學習基礎知識。我正在使用終端啟動腳本,例如“./scriptgoeshere.sh Argument1 Argument2”。

我希望腳本列印一些回顯,「Hello World」可能是最好使用的一個,但我只希望它在以下情況下列印出 hello world: 恰好有兩個參數,並且這些參數必須僅由數字組成。例如:

./scriptgoeshere.sh 1523 9643 ./scriptgoeshere.sh 7 96 應該可以,但是; ./scriptgoeshere.sh 594 arg 不應該工作,這是我目前的腳本,但它不起作用,我一整天都在嘗試解決這個問題,但似乎無法解決它,我什至嘗試過if/elif/ else我在繼續之前檢查 if 部分中是否有 2 個輸入,以及它們是否都是 elif 中的數字。

#!/bin/bash
if [ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ]; 
then
    i=0
    while [ $i -lt 3 ]
    do
        echo "Hello World!"
        sleep 5
        i=$((i+1))
    done
else
echo "Need two arguments and only numbers will be accepted, such as ./scriptgoeshere 153 251"

fi

它會阻止 hello world 循環,直到我輸入 2 個參數,但它們是數字還是文字並不重要,然後我收到錯誤:「./scriptgoeshere.sh: line 2: [: ^[0-9]:預期的整數表達式」。即使我在終端機中寫入 ./scriptgoeshere.sh 123 123 來啟動它,我也會收到該錯誤。我不想透過變數來解決它,因為我想在啟動實際腳本時找出參數。

這讓我很頭痛!

這就是我開始檢查是否剛好有 2 個參數並且它有效的方法,我只是想對其添加一個小修復,以便這 2 個參數必須是數字。我不明白為什麼看起來這麼難。

#!/bin/bash
if [ "$#" -eq 2 ];
then
    i=0
    while [ $i -lt 3 ]
    do
        echo "Hello World!"
        sleep 1
        i=$((i+1))
    done
else
echo "Need two argument, only numbers accepted"

fi

編輯:我解決了。我已經工作得非常接近了..我只需要在 if 字串的數字部分添加額外的 [] 。有人知道為什麼它需要寫成 [[ "$@" -eq ^[0-9] ]] 而第一部分可以只寫一個 [] ?

答案1

起初[ "$#" -eq ^[0-9] ][ "$@" -eq ^[0-9] ](這個問題在我寫答案時被編輯了......)。從上下文來看,我認為您想測試參數是否是數字。

  • $#始終是一個數字,以十進位表示的位置參數的數量。您想要測試兩個位置參數:$1$2
  • [是一個命令([ whatever ]相當於test whatever)。它可能是內建的 shell,但在語法上它就像lsman。 shell 解析後面的單字(包括]),就像命令後面的任何單字一樣:shell 擴展它們(例如,$#變成數字),刪除引號;最終它們成為 的參數[。這些擴展之一是檔案名稱擴展,其中各種模式與現有檔案名稱相符(檔案名稱擴展、通配符)。如果這些檔案存在,則未加引號的內容^[0-9]可能會擴展為。^2 ^5如果沒有符合項目或停用該功能,^[0-9]則將按字面意思取得[(作為其參數之一)。它看起來像一個模式,但[無論如何都不支援模式匹配。
  • -eq要求前一個和下一個參數都是整數。$#肯定會擴展為整數。在這種情況下無法^[0-9]擴展到數字。
  • 雙引號$@很特殊,儘管被引用,但它可以擴展到多個單字(POSIX 術語中的“字段”)。通常我們引用是為了防止分詞:"$foo"即使值包含空格等,也會擴展為一個單字。"$@"像 一樣擴展"$1" "$2" …,它的雙引號阻止$1擴展為多個單字(以及單獨的$2等等)。在這個片段中:

    [ "$#" -eq 2 ] && [ "$@" -eq ^[0-9] ]
    

    第二個[是運行當且僅當第一個成功(這就是&&工作原理),即當且僅當有兩個位置參數。在這種情況下"$@"相當於"$1" "$2"第二個測試變成

    [ "$1" "$2" -eq ^[0-9] ]
    

    這沒有道理。[可能會根據參數的實際值和 的擴展以不同的方式抱怨^[0-9],但它仍然是垃圾。


現在關於[[ "$#" = [0-9] ]].

注意:此片段位於問題的第一次修訂中。當我撰寫答案時,該問題已被編輯。我決定保留這個片段,因為[[無論如何最終可能會有用。

  • 再次強調:$#始終是個數字。
  • [[不等於[.您可以使用的任何理智測試[都可以重寫[[(儘管您不應該通過僅替換為來盲目地執行此操作[[[。還有額外的測試[[可以做,它的功能更強大。雖然[(and test) 是 POSIX 所要求的,但[[不是。

    重要的是:[[不是像lsor 這樣的命令[。它是一個關鍵字,它改變了 shell 解析後面單字的方式。[[和之間的所有內容]]都會以不同的方式解析。

    如果運算符是=,則下一個參數是模式。某些字元/語法(例如*[0-9])在未加引號時會與 先前的參數進行比對=。這就像檔案名稱擴展,但不針對現有檔案名稱。您的程式碼測試了(擴充)是否$#恰好是一位數字。整個測試是

    [[ "$#" -eq 2 ]] && [[ "$#" = [0-9] ]]
    

    foo && barbar當且僅當成功時運行foo。只有在擴展為 時才[[測試第二個,因此它必須成功,因為恰好是一位數字。在這種情況下,第二個沒有任何改變。$#22[[


假設您意識到自己的錯誤並測試了是否$1為一個數字。

  • 如上所述,如果擴展到恰好一位數字,[[ "$1" = [0-9] ]]則返回成功。$1
  • [[ "$1" = [0-9][0-9] ]]– 正好兩位數。
  • [[ "$1" = [0-9]* ]]– 以數字開頭的東西。

偵測您需要的任意數量的數字=~。裡面的這個運算子[[ ]]有點類似=,但現在的模式是一個擴充的正規表示式。不過,它不需要將整個字串匹配到運算符的左側,一個子字串就足夠了(因此在您的情況下需要錨點)^$

  • [[ "$1" =~ [0-9] ]]$1如果擴展為包含數字的字串,則傳回成功。
  • [[ "$1" =~ [0-9][0-9] ]]– …包含兩個相鄰的數字。
  • [[ "$1" =~ ^[0-9]$ ]]– 恰好是一位數字的字串。
  • [[ "$1" =~ ^[0-9]*$ ]]– 零個或多個數字。
  • [[ "$1" =~ ^[0-9][0-9]*$ ]]– 一位或多位數字。
  • [[ "$1" =~ ^[0-9]+$ ]]– 一位或多位數字。

[[ "$1" =~ ^[0-9]+$ ]]以及[[ "$2" =~ ^[0-9]+$ ]]您可能想要的測試。為了允許前導-修改它們,如下所示:[[ "$1" =~ ^-?[0-9]+$ ]].整個測試片段可能是

[ "$#" -eq 2 ] && `[[ "$1" =~ ^-?[0-9]+$ ]]` && `[[ "$2" =~ ^-?[0-9]+$ ]]`

內部[[ ]]變數/參數不能用雙引號引起來,而且它們的擴展值不會進行分詞和通配。所以你可以寫[[ $1 =~ ^-?[0-9]+$ ]],而且很安全。這是一個例外;一般來說,你應該用雙引號變數。這裡雙引號不會幹擾任何事情,所以我建議無論如何都要引用以習慣這種良好的一般實踐。


您聲稱您使用 解決了問題[[ "$@" -eq ^[0-9] ]]。對不起,我不相信你。如果恰好有兩個位置參數並且它們是數字,我看不出這在語法上是正確的,更不用說測試你想要的了。在其他情況下……我仍然沒有找到辦法。

……使用[[ "$@" =~ ^[0-9] ]](來自您的評論,與問題不連貫)。這不是一個正確的解決方案。我的測驗顯示"$@"inside 的[[ ]]行為就像未加引號的一樣$@,被視為一個單詞,沒有分詞和通配符。這與常規變數在內部的行為非常相似[[ ]],儘管事先對我來說並不明顯,因為我知道"$@"它不像常規變數。

附註:基於這個原因,我從來不想使用"$@"inside [[ ]]。我無法想像當它是正確的時候的場景。

當恰好有兩個位置參數時,您的“解決方案”變為[[ "$1 $2" =~ ^[0-9] ]]。它在語法上是有效的,它檢查腳本的第一個參數的第一個字元是否是數字。只有這個。運行./scriptgoeshere.sh 0h well,參數將通過測試。


筆記:

  • [0-9](作為通配模式或正規表示式)取決於您目前的區域設定。它很可能會按您的預期工作,但從技術上講,可能有一個區域設置,其中9before0或 where 2is Beyond 0-9。匹配數字的最通用方法是[[:digit:]]。看

    另一方面,您可能想要使用$1and/or$2與 shell 算術 ( $((…)))[ "$1" -ge 50 ]等。那你只需要阿拉伯數字。即使[[:digit:]]將它們包含在您的區域設定中(可能確實如此),它也可能包含其他數字。考慮[0123456789];它是明確的並且不依賴語言環境。

  • 從and/or^-?[0-9]+$的角度來看,並非每個符合的字串都被視為整數(例如,當您這樣做時)。每個工具都有一個可以處理的整數範圍。同樣,如果您向 shell 算術輸入描述超出範圍整數的數字字串,則 shell 算術可能會產生數學上錯誤的結果。[[[[ "$1" -eq 0 ]

  • 數學上1.00是一個整數。有些工具可能會接受它作為整數,有些可能不會。關於什麼1e100

相關內容