Bash

函式中的“cd”有效,除非它不起作用

  • August 14, 2022

cd 到目錄後我做的第一件事是使用“ls”,我想很多人都是這樣。所以我決定在我的 .bashrc 中定義一個函式來一起做。這就是我想出的:

cs() {
   if [[ ! "$1" ]] && [[ ! "$HOME" ]]
   then
       echo "I am completely lost and can't go home!"
       exit 1
   fi
   cd "$1" && ls --group-directories-first -h --color=auto
}

這在所有情況下都有效,但有一種情況:當我沒有傳遞任何參數時。無論是否設置了 $HOME ,它都不會執行任何操作並退出。我最終肢解了第一行並得出了這個結論:

cs() {
   if [[ ! "$1" ]]
   then
       if [[ ! "$HOME" ]]
       then
           echo "I am completely lost and can't go home!"
           exit 1
       else
           cd && ls --group-directories-first -h --color=auto
       fi
   else
       cd "$1" && ls --group-directories-first -h --color=auto
   fi
}

這段程式碼完全按照我的意圖工作。在這兩者之間,我有一個行為非常奇怪的版本(不幸的是我保存了它,但是這兩個版本的差異非常小)如果我用參數喚起“cs”,它會給我輸出該目錄的“ls”…但不會更改目錄!由於程式碼只是將參數傳遞給“cd”,而 ls 又回到了在目前目錄上工作的預設行為(在這個失去的版本中也是如此),而且我從來沒有放過第二個“cd” " 在同一程式碼塊中的 “ls” 之後,據我所知,這甚至是不可能的。

我只是想了解這裡發生了什麼。我剛剛開始學習腳本,我認為這將是一個非常簡單的任務,似乎已經變成了一個很好的學習機會。為什麼這些在我看來幾乎等同的功能表現不同?

您只需要cd使用為函式提供的原始參數列表執行,然後執行您的ls命令。

cs () {
   cd "$@" && ls --group-directories-first --human-readable --color=auto
}

如果沒有使用任何參數呼叫函式,則擴展"$@"將毫無意義,從而導致cd更改到目前使用者的主目錄或以任何適當的方式失敗。否則擴展將是引用的參數列表(請注意,cd通常可以採用多個參數)。

cd命令的內在邏輯已經處理了未設置未接收參數的情況HOME,因此您的函式不必參與其中。

通常,您可能希望避免使用exitin 函式,因為這會退出目前 shell。相反,如果您希望從函式返回非零退出狀態,請使用,例如return 1.

至於您關於cd未成功更改目錄的評論:如果您在子shell中執行您的函式(或只是cd),例如在(cd /)cat somefile | while ...; do cd ...; done(管道的每個部分在子shell中執行)中,則可能會發生這種情況。呼叫成功,cd目前目錄發生了變化,但是這些變化是針對子shell的本地環境進行的,在父shell中是不可見的。子 shell 無法更改其父 shell 的環境。

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