Почему ваша функция не работает
Есть несколько причин:
- Я предполагаю, что
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
обрезает строку, обрабатывая пробел как разделитель (-d " "
) и оставляя второе поле и все, что следует за (-f 2-
), т.е. все после первого пробела. Работает со строками с нулевым символом в конце (-z
). Окончательный вывод - это желаемое имя каталога.
Обратите внимание, что вывод будет пустым, если в текущем рабочем каталоге нет каталога.
$(…)
Заменяется выводом всего, что находится внутри. На данный момент у нас есть либо cd "some directory name"
либо cd ""
. Первая команда делает то, что вы хотите; последний (когда нет каталога) ничего не делает.
Функция потерпит неудачу, если каталог, в который она должна cd
будет (пере) перемещен / переименован после того, как find
найдет его. Кроме того, stat
может выдавать ошибки, если какой-либо каталог перемещается / переименовывается, когда функция работает.