[英]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
擴展到比( -nt
) mrd
更新的目錄,那么我們用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.