如何最大限度地減少運行此自訂函數所需的程式碼?

如何最大限度地減少運行此自訂函數所需的程式碼?

我想縮短我的一個腳本,我不知道該怎麼做。有一段這樣的程式碼:

COMMAND="find /etc -type "
case $1:
 "directory") $COMMAND d
 ;;
esac

當然這是簡短的版本:) 現在我希望能夠縮短它,而不是到處寫 $COMMAND,所以我想要這樣的東西:

$COMMAND <the case statement return value>

但我不想使用變數來儲存案例的結果。

謝謝:)希望你明白我想要什麼:D

編輯 1:可以建立一個函數並將 find 參數作為 Serg 指出的 $1 傳遞。現在,如果我想在沒有函數的情況下做到這一點,我確信有一種方法:D 不像 Serg 沒有解決它,我只是好奇:D

答案1

有幾種可能的方法可以簡化程式碼。以下是按代碼量排序的解決方案:

  1. printf和參數替換(無錯誤檢查)
  2. xargs和參數替換(無錯誤檢查)
  3. find僅參數替換(無錯誤檢查)
  4. 失敗案例結構(解決錯誤檢查問題)
  5. 測試邏輯、xargs 和參數替換
  6. bash函數
  7. 陣列、for 迴圈、測試和 &&

  1. printf和參數替換解決方案

    該函數的一個鮮為人知的特點printf是,如果您調用printf "%c" someString,它只會列印第一的該字串的字元。因此,我們可以避免使用帶有參數擴展的 case 語句,printf如下所示:

    xieerqi:$ cat someScript.sh
    #!/bin/bash
    find /etc -type $(printf "%c" $1 )
    

    現在執行:

    xieerqi:$ sudo ./someScript.sh  directory | head
    [sudo] password for xieerqi: 
    /etc
    /etc/logrotate.d
    /etc/apm
    /etc/apm/event.d
    /etc/apm/scripts.d
    /etc/apm/resume.d
    /etc/apm/suspend.d
    /etc/speech-dispatcher
    /etc/speech-dispatcher/modules
    /etc/speech-dispatcher/clients
    

    這裡的一個限制是我們分叉一個進程來調用printf,函數解決方案避免了這一點 - 函數和 case 結構都是本機 bash 工具。

  2. xargs和參數替換

    使用 bash 的參數替換,我們可以從變數中截取子字串(例如${VAR:0:3}給出 的前 3 個字元VAR);在這種情況下,我們想要類型的第一個字元directoryfile。然後我們可以xargs將其作為參數傳遞給find

    echo ${1:0:1} | xargs -I {} find /etc -type  {} 
    

    手冊find頁提到,對於-typeSolaris 上的標誌,有一種稱為「門檔案」的東西,用大寫字母 表示D,但由於我們使用的是 Linux,所以我們可以說這是一個可以合理忽略的限制。

    然而,這段程式碼還有另一個危險 - 如果用戶輸入flower作為$1參數,這仍然會搜索-type f,因為我們採用任何字串的第一個字元......換句話說,沒有錯誤檢查

  3. find帶參數擴展

    進一步擴展參數,我們可以這樣做:

     find /etc -type ${1:0:1}
    

    基本上,是一個帶有find命令和變數子字串的單行程式碼$1另外,沒有錯誤檢查

  4. 失敗案例結構

    最後三種方法的最大問題是錯誤檢查。當您相信用戶不是假人,或只是為自己編寫程式碼時,它們就很好。現在,在 Java 中,如果您只是省略該命令,則可以編寫一條switch語句,該語句將在多種情況下執行相同的命令break。終結者bash也可以做到這一點;&。引用自man bash

    使用;&in 代替;;會導致執行繼續與下一組模式關聯的清單。

    我們要做的就是測試類型,例如「目錄」、「檔案」、「區塊」等,然後使用參數替換來截掉第一個字元。像這樣

    #!/bin/bash
    case "$1" in
      "directory") ;&
      "file");&
      "block") find /etc -type  ${1:0:1} ;;
      *) exit 1 ;;
    esac
    

5.測試邏輯、xargs 和參數替換

 Basic idea here is that we're sending $1 variable through pipe to `xargs`, which in turn substitutes it into test (again square brackets). `xargs` in turn builds the actual command that runs by replacing `{}` with whatever was passed to `xargs`.  As for test command, it's simple or statement,  `EXPRESSION -o EXPRESSION ` , where we test if string $1 is equal to either "file" or "directory string"

    echo "$1" | xargs -I {}  [ "{}" = "file" -o "{}" = "directory"  ] \
    && find /etc -type ${1:0:1}

 `xargs` is really useful when you need to process multiple argumens with the same command. Considering that in this case we only have one argument that needs to be processed with the same command , this can be simplified to

    [ "$1" = "file" -o "$1" = "directory"  ] && find /etc -type ${1:0:1} 

Of course the big limitation is that if you test for more than one type, you need longer `[ EXPR1 -o EXPR2 ]` structure with multiple `-o` parts.
  1. 功能解決方案

    find命令可以放入函數中,然後可以使用位置參數呼叫函數。

    例如:

    function findStuff
    {
     find /etc -type "$1" 
    }
    

    這是一個小演示。請注意,我使用的是sudo因為普通用戶的許多檔案/etc沒有讀取權限

    xieerqi:$ sudo ./someScript.sh directory | head                                            
    [sudo] password for xieerqi: 
    /etc
    /etc/logrotate.d
    /etc/apm
    /etc/apm/event.d
    /etc/apm/scripts.d
    /etc/apm/resume.d
    /etc/apm/suspend.d
    /etc/speech-dispatcher
    /etc/speech-dispatcher/modules
    /etc/speech-dispatcher/clients
    
    xieerqi:$ sudo ./someScript.sh file | head                                                 
    [sudo] password for xieerqi: 
    /etc/hosts.deny
    /etc/logrotate.d/speech-dispatcher
    /etc/logrotate.d/pm-utils
    /etc/logrotate.d/rsyslog
    /etc/logrotate.d/yate
    /etc/logrotate.d/apport
    /etc/logrotate.d/apt
    /etc/logrotate.d/consolekit
    /etc/logrotate.d/fail2ban
    /etc/logrotate.d/cups-daemon
    
    xieerqi:$ cat someScript.sh                                                                
    #!/bin/bash
    function findStuff
    {
     find /etc -type "$1" 
    }
    
    case "$1" in 
      "directory")findStuff d ;;
      "file") findStuff f;;
    esac
    
  2. 陣列、for 迴圈、測試和 &&

    這裡的基本想法 - 將使用者的輸入與清單進行匹配,如果匹配則執行某些操作。我們建立一個要檢查的項目數組,設定一個測試條件(方括號是test指令的別名),然後執行一個迴圈來測試 $1 變數。&&當且僅當左側的內容&&成功時,運算子才允許執行指令。因此,如果我們在數組中找到一個字串,我們就會執行 find 命令。 ${1:0:1} 在前面的範例中討論過 - 參數擴充功能會從我們符合的類型中刪除第一個字元。因此,此解決方案具有錯誤檢查功能,並將全部程式碼打包為僅 3 行(如果包含#!行,則為 4 行)。

    #!/bin/bash   
    array=("file" "directory" "block");
    for TYPE in "${array[@]}"; do 
       [ "$1" = "$TYPE"  ] && find /etc/ -type ${1:0:1}; 
    done  
    

答案2

將其放入函數中:

MyFind () {
  COMMAND="find /etc -type "
  case $1:
   "directory") $COMMAND d
   ;;
  esac
}

現在您可以隨時將其用作MyFind $TYPE


關於您的第一則評論

您也可以只將 case 語句放入函數中

FType () {
  case $1 in
    "directory") echo d;;
    "file") echo f;;
  esac
}

COMMAND="find /etc -type "
$COMMAND $(FType $TYPE) 

答案3

[[ "$1" == "directory" ]] && find /etc -type d

答案4

這只是 Serg 出色答案中已經廣泛的選項的另一個想法。

您也許可以使用 analias來實現此目的 - 可能會對您目前的工作方式進行一些細微的更改。

Analias只是您選擇映射到更大字串的單詞,shell 每當遇到它時都會擴展該字串。也許最常見的用例是將“預設值”應用於現有命令,如下所示:

alias ls='ls -a --color=auto'

但是,不要求您alias必須以現有命令命名 - 或甚至比其目標模式短 - 所以您可以例如alias tgzcreator='tar -czvf'

aliases 與定義它們的 shell 共享生命週期。alias可以為您設定“持久” ~/.bash_aliases,其中應該.bashrc由大多數編寫良好的預設腳本等自動取得。

請注意一些提示:

  • 您不必擔心特定腳本中先前定義的內容是否alias會幹擾您的程式碼,而是可以在其前面加上反斜線以確保alias跳過 ing。例如,我通常alias cpcp -i避免意外覆蓋某些內容,但在某些腳本中,我顯然覆蓋一些東西。 (我不會使用一些可怕的解決方法,例如設定已知的未alias編輯用戶!)因此,在該腳本中,我將使用\cp src dst
  • alias預設情況下,es 可能不會在 shell 腳本中獲取,這些腳本會啟動它們自己的 shell 的非互動式副本。您可以透過expand_aliases在腳本中設定選項來確保它們擴展。我從以下地方得到這個:https://stackoverflow.com/questions/2197461/how-to-set-an-alias-inside-a-bash-shell-script-so-that-is-it-visible-from-the-ou

因此,根據您帖子中可用的有限上下文,您可能想做一些事情有點像這樣:

shopt -s expand_aliases
alias get_etc_dir='find /etc -type d'
alias get_etc_fil='find /etc -type f'

對於您來說,如果不進行調整,這可能無法運作,例如將參數化 inode 類型變更為每個別名後綴。這只是用戶如何縮短一般代碼位的另一種選擇。無論哪種方式,我都試圖根據我所知道的進行全面解釋,希望它在某些地方有用。

(另外,我建議將其移至 Unix/Linux SE,假設這對於非 Ubuntu 特定的事物來說是理想的選擇?)

相關內容