Вызов функции bash не работает, как следует изменить на недавний каталог?
Поэтому я ожидаю, что моя функция изменится на недавно измененный каталог.
Это оно:
function cdrc { echo 'cd "$(ls -t | HEAD -1)"'; }
Когда я хочу перейти на недавний каталог:
- Показать дубликаты данных с awk print $ 2, $ 3, $ 4 в одной строке
- Как извлечь два числа из двух строк и рассчитать разницу в Bash?
- Как отфильтровать строку с подстановочным знаком и вывести ее в другой текстовый файл с модификацией?
- Как grep и печатать следующие N строк после удара?
- Удаление файлов старше 1 месяца, но оставить файлы, созданные в первый день месяца
$~ cd Desktop/Folder $~ cdrc
Я получил:
–bash: Рабочий стол: команда не найдена
- Bash: использовать столбцы отдельно в массиве
- Написание сценариев оболочки, которые будут выполняться на любой оболочке (используя несколько строк shebang?)
- Howto переключить / chage идентификатор пользователя с помощью скрипта bash для выполнения команд в том же скрипте?
- Messaging.sh: строка 29: '
- Является ли это специфичным для bash методом вызова скрипта: VARIABLE = value bash somescript
- Как сохранить вывод верхней команды в формате XML?
- Передача двух аргументов команде с использованием труб
- Отображение стека соединений ssh в терминале
Почему ваша функция не работает
Существует несколько причин:
- Я думаю,
echo
– это артефакт, используемый для тестирования синтаксиса или так. Не имеет смысла, если вы хотите, чтобы функция выполняла то, что вы описали. - Верхний
HEAD
. В Linux это должно бытьhead
. Я не уверен в других ОС, где вы можете запускатьbash
иhead
.HEAD
может работать или не работать в некоторых из них, ноhead
должна работать повсюду. - Разбор
ls
не рекомендуется. Об этом есть статья . Главное в вашем случае было бы то, чтоls
не может надежно печатать имена, включая специальные или непечатаемые символы. - Нет никакой логики, чтобы тестировать только каталоги, вы можете в конечном итоге попробовать
cd
к файлу, когда нет каталога. - Нет никакой логики для обработки ситуации, когда текущий рабочий каталог пуст.
Все эти проблемы можно отладить, кроме этой ls
. Это недостаток дизайна. Если вы считаете, что ограничения ls
не укусят вас, вы можете пойти с решением из этого другого ответа .
Чтобы выполнить некоторые тесты, вы можете создать неприятный каталог с mkdir "$(echo -ne "foo\nbar")"
; cdrc
решения, вероятно, не cdrc
если это каталог cdrc
должен cd
to. Чтобы удалить неприятный каталог, вызовите 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 " ")" ;}
объяснение
Чтобы объяснить мою функцию, я напишу ее более четко. Обратите внимание, что a \
в самом конце строки говорит 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, секунды с Epoch), одно пробел и имя (%n
). Из-за опции--printf
он не добавляет символ новой строки, а интерпретирует\0
как нулевой символ, который должен быть добавлен в конце каждой строки. -
{}
Является частью синтаксисаfind -exec
. Во время выполненияfind
он заменяется именем каталога, поэтомуstat
знает, какова его цель. -
+
Также является частью синтаксисаfind -exec
. Это заставляетfind
передавать несколько имен в одинstat
(иstat
может обрабатывать его). Таким образом, создается меньше процессовstat
, это быстрее.
-
В этот момент у нас есть ноль или более строк. Они выглядят примерно так:
1493488341 directory name 1497365306 troublesome?directory name
Но они заканчиваются на нуль, поэтому, даже если есть имена с неприятными символами, они будут обрабатываться надлежащим образом. В первом столбце есть mtimes без начальных пробелов (я проверял поведение stat
с номерами различной длины, чтобы убедиться), тогда первое пространство отделяет mtime от имени каталога.
- Этот выход обрабатывается следующим образом:
- Сортирует строки по цифровому значению (
-n
), использует обратный порядок (-r
) и работает с нулевыми символами (-z
). Таким образом, каталог, в котором мы нуждаемся, теперь находится в первой строке. - Затем
head
оставляет только первую строку (-n 1
); Ему также говорят работать с нулевыми символами (-z
). - Разрезает линию, обрабатывая пространство как разделитель (
-d " "
) и оставляя второе поле и все, что следует (-f 2-
), т.е. все после первого пространства. Он работает с нулевыми символами (-z
). Конечный результат – это имя нужного каталога.
- Сортирует строки по цифровому значению (
Обратите внимание, что выход будет пустым, если в текущем рабочем каталоге нет каталога.
-
$(…)
заменяется выводом всего, что внутри. На данный момент у нас есть либоcd "some directory name"
либоcd ""
. Первая команда делает то, что вы хотите; Последний (когда нет каталога) ничего не делает.
Функция будет терпеть неудачу, если каталог, к cd
он должен cd
будет (re) перемещен / переименован после find
как find
найдет его. Также stat
может вызывать ошибки (ошибки), если какой-либо каталог (re) перемещается / переименовывается, когда функция работает.
Если вы хотите включить все каталоги, то есть начиная с точки
function cdrc { cd "$(ls -1atp|grep -v '^\.\.\?/$'|grep '/$'|head -1)"; }
Иначе намного проще
function cdrc { cd "$(ls -1tp|grep '/$'|head -1)"; }