-2

Поэтому я ожидаю, что моя функция изменится на недавно измененный каталог.

Это оно:

function cdrc { echo 'cd "$(ls -t | HEAD -1)"'; }

Когда я хочу перейти на недавний каталог:

$~ cd Desktop/Folder
$~ cdrc

Я получил:

-bash: рабочий стол: команда не найдена

2 ответа2

1

Почему ваша функция не работает

Есть несколько причин:

  • Я предполагаю, что 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 передавать несколько имен одному statstat может с этим справиться). Таким образом, создается меньше процессов 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 может выдавать ошибки, если какой-либо каталог перемещается / переименовывается, когда функция работает.

0

Если вы хотите включить все каталоги, т.е. начиная с точки

function cdrc { cd "$(ls -1atp|grep -v '^\.\.\?/$'|grep '/$'|head -1)"; }

В противном случае гораздо проще

function cdrc { cd "$(ls -1tp|grep '/$'|head -1)"; }

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .