Linux

如何在命令中傳遞參數而不執行參數內容?

  • May 14, 2022

好日子。

我有一個小問題。我在 bash 腳本中有這個功能

function denyCheck(){
   file=$(readlink -f $(which $(printf "%s\n" "$1")))
   if [[ -x $file ]];then
          return false
   else
          return true
   fi
}
denyCheck "firefox"

這個函式我向她傳遞了一個字元串,什麼是命令,這解決了命令所在的原始路徑(例如:/usr/lib/firefox/firefox.sh),如果文件是可執行的,則返回 true,否則返回 false。

但問題是…參數(在範例中為“firefox”)將其作為命令執行並打開瀏覽器 firefox。

我該怎麼做才能使參數不執行它?

非常感謝。

應該是:

cmd_canonical_path() {
 local cmd_path
 cmd_path=$(command -v -- "$1") &&
   cmd_path=$(readlink -e -- "$cmd_path") &&
   [ -x "$cmd_path" ] &&
   REPLY=$cmd_path
} 2> /dev/null

然後使案例如:

if cmd_canonical_path firefox; then
 printf '%s\n' "firefox found in $REPLY executable"
else
 printf >&2 '%s\n' "no executable file found for firefox"
fi

在 shell 中,所有命令都有一個退出狀態,指示成功 (0) 或失敗(任何其他數字,其值可以幫助區分不同類型的失敗)。

例如,如果執行該命令的程序對文件(或目錄)具有執行權限,則該[命令在傳遞-x和as 參數時將返回 true。/path/to/some/file``]``/path/to/some/file

一個函式也可以有一個退出狀態,這是它在返回之前執行的最後一個命令的退出狀態(或者return如果在那裡呼叫,則傳遞給的數字)。

命令的成功或失敗狀態由 shell 結構檢查,例如if//語句until或其while布爾運算符||&&. 如果您願意,命令是 shell 的布爾值。

cmd1 && cmd2 && cmd3返回成功 / true 是全部cmd1cmd2並且cmd3成功。如果失敗,cmd2甚至不會執行cmd1,對於cmd3.

因此,cmd_canonical_path如果command -v -- "$1"(用於查找命令並輸出其路徑的標準內置¹命令²;雖然which是一些類似的命令,但僅適用於 csh 使用者)然後readlink -e成功(類似於規範化readlink -f路徑,但如果不能,則會返回失敗) whilereadlink -f將盡最大努力)成功**,**然後目前程序對該文件具有執行權限,然後(並且僅在那時)將該路徑成功分配給REPLY4變數(普通分配總是成功的)。

如果不是,該函式將返回失敗:該cmd && cmd && cmd鏈中第一個失敗的命令的退出狀態。

您還會注意到,$REPLY如果無法確定該命令的規範路徑或您無法執行該命令,則該命令將被單獨保留且不會被修改。

您的方法的其他一些問題:

  • $(printf '%s\n' "$1")沒有多大意義。在 sh/bash 中,它與$1(至少在預設值 的情況下$IFS)相同,並且同樣錯誤,因為它沒有被引用。如果要將第一個位置參數的內容傳遞給命令,則語法為cmd "$1".
  • 當您希望傳遞給命令的一些任意數據被視為非選項參數時,您需要在--標記選項結束的參數之後傳遞它:which -- "$1", readlink -f -- "$(...)".
  • return將(可選)數字作為參數(函式的退出程式碼),而不是true/ false(您似乎也將它們顛倒了,因為您說如果文件是可執行的,函式將返回 true)。如果未傳遞數字,則函式的退出狀態將是函式中執行的最後一個命令的退出狀態。所以if cmd; then return 0; else return 1; fi最好寫成 just cmd; return。雖然在這裡你甚至不需要return因為cmd[[ -x $file ]]在你的情況下)是你函式中的最後一個命令。
  • 您在沒有首先檢查它是否成功的情況下盲目地傳遞which(錯誤地因為您忘記了--和引用$(...))的輸出。readlink

最後一點,如果您使用zsh代替bash,您可以這樣做:

firefox_path==firefox
firefox_canonical_path=$firefox_path:P

獲取firefox命令的路徑。=firefox展開到firefox命令的路徑,如果找不到,則中止 shell 並返回錯誤。如果需要,您可以在一個*always塊*中攔截該錯誤。:P修飾符對它所應用的參數執行realpath()等效操作,類似於 GNUreadlink -f所做的。無需檢查執行權限,因為zsh=cmd運算符只會擴展為可執行的路徑。


¹ 並且由於它是 shell 的內置功能,您可以在 shell 手冊中找到它的文件。對於bash,參見info bash command例如。

² 需要注意的是,command -v cmd輸出cmdcmd一個函式或 shell 內置,這可能是一個問題。

³ 一個規範的絕對路徑以 開頭/,沒有符號連結組件(它們都被解析為它們的目標),沒有./組件,沒有兩個或多個s 的..序列。/

4 $REPLY通常使用(儘管這只是一個約定)作為函式或 shell 內置函式的預設變數以返回值。或者,您的函式可以輸出結果,呼叫者將執行firefox_path=$(cmd_canonical_path firefox).

引用自:https://unix.stackexchange.com/questions/702494