Почему ваша функция не работает
Есть несколько причин:
- Я думаю
echo
, это артефакт, используемый для проверки синтаксиса или около того. Нет смысла, если вы хотите, чтобы функция делала то, что вы описали. - Прописные
HEAD
. В Linux это должно бытьhead
. Я не уверен насчет других ОС, где вы можете запуститьbash
иhead
.HEAD
может или не может работать в некоторых из них, ноhead
должно работать везде. - Разбор
ls
не рекомендуется. Об этом есть статья . Главное в вашем случае было бы то, чтоls
не может надежно печатать имена, включая специальные или непечатные символы. - Нет логики проверять только каталоги, вы можете в конечном итоге пытаться
cd
получить файл, когда каталога нет. - Нет логики обрабатывать ситуацию, когда текущий рабочий каталог пуст.
Все эти проблемы могут быть отлажены, за исключением этого анализа ls
. Это недостаток дизайна. Если вы думаете, что ls
ограничения не будут вас сдерживать, вы можете найти решение из этого другого ответа .
Для выполнения некоторых тестов вы можете создать проблемный каталог с mkdir "$(echo -ne "foo\nbar")"
; ls
решения на основе, вероятно, потерпят неудачу, если это каталог cdrc
должен cd
. Чтобы удалить проблемный каталог, вызовите rmdir "$(echo -ne "foo\nbar")"
.
Мне удалось создать более безопасную функцию.
Решение
function cdrc { cd "$(find -maxdepth 1 -mindepth 1 -type d -exec stat --printf "%Y %n\0" {} + | sort -znr | head -zn 1 | cut -f 2- -d " ")" ;}
объяснение
Чтобы объяснить мою функцию, я напишу это более четко. Обратите внимание, что \
в самом конце строки говорится, bash
что команда продолжается на следующей строке; поэтому мой код ниже рассматривается как однострочный, его можно вставить целиком в интерактивный bash
.
function cdrc { \ cd "$( \ find -maxdepth 1 -mindepth 1 -type d -exec \ stat --printf "%Y %n\0" {} + | sort -znr | head -zn 1 | cut -f 2- -d " " \ )" \ ;}
Процедура выглядит следующим образом:
- Сначала
find
выполняется. Он не спускается в подкаталоги (-maxdepth 1
), он также не находит текущий каталог (-mindepth 1
). Он находит только каталоги (-type d
). Затемstat
команда запускается (спасибо-exec
):stat
печатает время последней модификации данных (%Y
, mtime, секунды с начала эпохи), один пробел и имя (%n
). Благодаря--printf
опции он не добавляет символ новой строки, но интерпретируется\0
как нулевой символ, который должен быть добавлен в конце каждой строки.{}
является частьюfind -exec
синтаксиса. Во времяfind
выполнения он заменяется именем каталога, поэтомуstat
знает, какова его цель.+
также является частьюfind -exec
синтаксиса. Это приводитfind
к передаче нескольких имен к одномуstat
(иstat
может справиться с этим). Таким образомstat
, создается меньше процессов, это быстрее.
На данный момент у нас ноль или более строк. Они выглядят примерно так:
1493488341 directory name 1497365306 troublesome?directory name
но они заканчиваются нулем, поэтому даже если есть имена с проблемными символами, они будут обработаны правильно. В первом столбце есть mtimes без начальных пробелов (я проверил stat
поведение с числами различной длины, чтобы быть уверенным), затем первый пробел отделяет mtime от имени каталога.
- Этот вывод обрабатывается в дальнейшем:
sort
сортирует строки в соответствии с числовым значением (-n
), использует обратный порядок (-r
) и работает со строками с нулевым символом в конце (-z
). Таким образом, каталог, который нам нужен, теперь находится в первой строке.- Затем
head
оставляет только первую строку (-n 1
); также сказано, что нужно работать со строками с нулевым символом в конце (-z
). cut
обрезает строку, обрабатывая пробел как delimiter (-d " "
) и оставляя второе поле и все, что следует (-f 2-
), т.е. все после первого пробела. Работает с пустыми строками (-z
). Окончательный вывод - это желаемое имя каталога.
Обратите внимание, что вывод будет пустым, если в текущем рабочем каталоге нет каталога.
$(…)
заменяется выводом всего, что внутри. На данный момент у нас есть либоcd "some directory name"
илиcd ""
. Первая команда делает то, что вы хотите; последний (когда нет каталога) ничего не делает.
Функция потерпит неудачу, если каталог, в который она должна cd
переместиться / переименована после того, как find
найдет ее. Также stat
может выдать ошибку (и), если какой-либо каталог был (пере) перемещен / переименован, когда функция работает