簡體   English   中英

別名命令更改為最新目錄

[英]alias command to change to newest directory

我想在我的bashrc文件中添加一個別名,以更改為當前目錄中的最新子目錄:

alias cdl="cd $(ls -t | head -n 1)"

問題是,當我獲取文件時,該命令僅被評估一次。 如果我在更改目錄后使用新的cdl命令,它仍然會嘗試更改為舊目錄,這可能不在我的新位置,並且對我來說並不是那么有用。

如何在每次運行時對此命令進行別名評估?

這是一種安全的方式來執行你想要的東西:安全我的意思是它會找到最新的目錄 (而不僅僅是你的情況下的文件,雖然這可以修復)如果目錄名包含空格,它將起作用, glob字符和換行符(可以通過添加適當的雙引號來修復你的空格和glob字符,但不能用於換行符 - 有些人會認為處理換行符是不必要的;但是因為它可能,為什么不能有一個健壯的命令?) 。

我們將使用函數而不是別名!

cdl() {
    local mrd
    IFS= read -r -d '' mrd < <(
        shopt -s nullglob
        mrd=
        for i in */; do
            if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
                mrd=$i
            fi
        done
        [[ $mrd ]] && printf '%s\0' "$mrd"
    ) && cd -- "$mrd"
}

演練

讓我們首先關注內部部分:

shopt -s nullglob
mrd=
for i in */; do
    if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
        mrd=$i
    fi
done
[[ $mrd ]] && printf '%s\0' "$mrd"

如果沒有匹配項,則nullglob shell選項將使globs擴展為空。 for i in */的循環中使用了一個glob,帶有一個斜杠,所以這會擴展到當前目錄中的所有目錄(如果沒有目錄,則沒有任何內容,這要歸功於nullglob )。

我們將mrd變量初始化為空字符串,然后循環遍歷所有目錄,循環變量i :如果mrd為空或者i擴展到比( -ntmrd更新的目錄,那么我們用i替換mrd

在循環之后,如果mrd仍然為空(如果沒有找到任何目錄就會發生這種情況)我們什么都不做; 否則我們使用尾隨的nullbyte打印該目錄名稱。

現在,外部:

IFS= read -r -d '' mrd < <( ... )

這將獲取上面討論的內部部分的輸出(因此,無論是什么或最近目錄的內容,具有尾隨的nullbyte)並將其存儲在變量mrd 如果沒有讀取任何內容,則read失敗,否則read成功。 如果成功,我們很高興在最新的目錄中cd


我想提兩點:

  • 可以將cdl寫成:

     cdl() { local mrd i for i in */; do if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then mrd=$i fi done [[ $mrd ]] && cd -- "$mrd" } 

    如您所見,這不會設置nullglob ,這是必需的。 但是你不想全局設置它。 所以你需要保存舊的nullglob

     local old_nullglob=$(shopt -p nullglob) 

    並在功能結束時重置它:

     eval "$old_nullglob" 

    雖然這很好,但我現在試圖避免這種情況,因為如果你的函數在完成之前退出(例如,如果用戶中斷它的執行),則nullglob將不會被重置。 這就是我選擇在子shell中運行循環的原因!

  • 此時,您可能會認為以下內容可以解決問題:

     local mrd=$( ... loop that outputs most recent dir... ) && cd -- "$mrd" 

    不幸的是, $(...)修剪了尾隨的換行符。 所以它不是100%工作,因此它被打破了。

事實證明,對我來說最健康的方法就是使用

IFS= read -r -d '' v < <( .... printf '...\0' )

如果你想要一個瘋狂的功能:你可能發現我給的cdl沒有處理隱藏目錄。 那么我們如何允許如下調用:

cdl .

那也將開啟搜索隱藏目錄? 等等,我們如何允許函數參數,以便調用就好

cdl . /path/to/dir1 /path/to/dir2 ...

cd到最新的/path/to/dir1/path/to/dir2等子目錄(包括隱藏的dirs)? 隱藏目錄的開關應該是第一個參數,所以

cdl /path/to/dir1 .

cd進入/path/to/dir1和當前目錄的最新非隱藏子目錄,但是

cdl . /path/to/dir1 .

還包括隱藏目錄。

cdl() {
    local mrd
    IFS= read -r -d '' mrd < <(
        [[ $1 = . ]] && shopt -s dotglob && shift
        (($#)) || set .
        shopt -s nullglob
        mrd=
        for d in "$@"; do
            if [[ ! -d $d ]]; then
                printf >&2 '%s is not a directory. Skipping.\n' "$d"
                continue
            fi
            [[ $d = / ]] && d=
            for i in "$d"/*/; do
                if [[ -z $mrd ]] || [[ $i -nt $mrd ]]; then
                    mrd=$i
                fi
            done
         done
        [[ $mrd ]] && printf '%s\0' "$mrd"
    ) && cd -- "$mrd"
}

我的下一個編輯將包括一個更新,允許調用cdl ,同時在計算π的最后一位數時也會沖泡咖啡。

如果你切換到單引號它應該工作:

alias cdl='cd -- "$(ls -t | head -n 1)"'

請注意,命令中的ls不一定提供最新的目錄 ,它也可能產生一個文件,在這種情況下命令將無法按預期工作。 在這方面,添加--group-directories-first選項可能會有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM