Как запустить одну команду с каталогом в качестве аргумента, а затем выполнить CD для того же? Я получаю «нет такого файла или каталога»

15

Я хотел бы построить короткую функцию, чтобы сделать следующее. Допустим, я переместил файл file.tex в каталог документов:

mv file.tex ~/Documents

Затем я хотел бы перейти cdв этот каталог:

cd ~/Documents

Я хотел бы обобщить это для любого каталога, чтобы я мог сделать это:

mv file.tex ~/Documents
follow

и попросите followкоманду прочитать назначение из предыдущей команды, а затем выполнить соответствующим образом. Для простого каталога это не экономит много времени, но при работе с вложенными каталогами было бы здорово иметь возможность просто использовать

mv file.tex ~/Documents/folder1/subfolder1
follow

Я думал, что это будет относительно просто, и что я мог бы сделать что-то вроде этого:

follow()
{
    place=`history 2 | sed -n '1p;1q' | rev | cut -d ' ' -f1 | rev`
    cd $place
}

но это не похоже на работу. Если я повторяю $place, я получаю желаемую строку (я проверяю ее ~/Documents), но последняя команда возвращает

No such file or directory

Каталог, безусловно, существует. Я в растерянности. Не могли бы вы помочь мне?

Пожар
источник
Я хотел бы отметить, что если вы не возражаете против сохранения file.texв исходном местоположении, символические ссылки являются очень хорошей альтернативой, поскольку вам нужно сделать ссылку только один раз, и тогда она всегда будет указывать на последнюю версию.
Кролтан
5
Более простой способ: введите cd alt +, .чтобы заменить последний токен предыдущей команды. Повторите, чтобы вернуться в историю финальных токенов. (Я говорю, что токен не аргумент, потому что foo &захватывает &в качестве окончательного токена.) Вы можете использовать числовой аргумент (например, с escape-3 alt +.).
Питер Кордес
см. также mkdir cd combo
Кристофер Боттомс,

Ответы:

18

Вместо определения функции вы можете использовать переменную $_, которая раскрывается до последнего аргумента предыдущей команды bash. Так что используйте:

cd "$_"

после mvкоманды.

Вы также можете использовать расширение истории:

cd !:$

Если вы должны использовать функцию:

follow () { cd "$_" ;}

$ follow () { cd "$_" ;}
$ mv foo.sh 'foo bar'
$ follow 
foo bar$ 

NB. Этот ответ нацелен на точный формат аргументов командной строки, который вы использовали, поскольку мы имеем дело с позиционными параметрами. Для других форматов, например mv -t foo bar.txt, вам нужно заранее включить определенные проверки, тогда будет уместна оболочка.

heemayl
источник
Ваше расширение истории (cd!: $) Работает отлично. Спасибо. Однако другой (cd "$ _") не имеет: mv file.tex ~ / Downloads / cd "$ _" bash: cd: __bp_preexec_invoke_exec: такого файла или каталога нет. Я с радостью приму ваш ответ как полностью правильный, и Спасибо.
Пожар
Я всегда печатал (несколько расточительно) либо cd !$или cd $(dirname !$). Не знал о $_переменной!
Калвин Ли
Что будет, если я сделаю это mv -t ~/Documents file.texвместо mv file.tex ~/Documents? В итоге, я не уверен, что это решаемо в общем случае ... функция обертки вокруг или что переопределения mvмогут быть лучше ...
CVn
@ MichaelKjörling Не сработает просто .. этот пример только для того, чтобы охватить случай, который имеет OP, а не крайние (или все) случаи ..
Heemayl
Вам не нужна толстая кишка; !$эквивалентно !:$и быстрее набирать.
Wildcard
14

При стандартных сочетаниях клавиш bash комбинация Alt.скопирует последний аргумент предыдущей командной строки в текущую. Итак, набрав

$ mv foo ~/some/long/path/
$ cd <Alt><.>

даст

$ mv foo ~/some/long/path/
$ cd ~/some/long/path/

и будет даже меньше печатать, чем слово follow .

Для дополнительного удобства повторяем Alt. комбинации будут просматриваться последние аргументы всех предыдущих командных строк.

Приложение: Имя команды bash, соответствующее этой комбинации клавиш, равно yank-last-argили insert-last-argument. Его можно найти на справочной странице bash в разделе «Команды для управления историей» или в более подробном справочном руководстве по Bash .)

Dubu
источник
1
Это умно. Благодарность! Я понятия не имел, что это существовало.
Пожар
@Fire Я добавил ссылки на эти команды, чтобы вы могли найти гораздо более интересные привязки клавиш (и сразу же забыть их снова, как я всегда делаю).
Дабу
1
Вы также можете использовать <esc>затем, .чтобы получить тот же результат, что <alt>+.и этот, полезный, когда вы переназначили capslock, чтобы убежать :)
gnur
1
@gnur vi (m) пользователь, я полагаю. ;-)
Dubu
6

Вы почти наверняка столкнетесь с проблемой, что расширение тильды происходит перед расширением параметра, что можно объяснить кратким примером:

$ cd ~kaz
kaz $ var='~kaz'
kaz $ echo $var
~kaz
kaz $ cd $kaz
bash: cd: ~kaz: No such file or directory

Это можно решить с помощью eval. В любом случае, вам это понадобится eval, потому что вы извлекаете команды из истории, и они могут содержать произвольные расширения, например:

$ mv file.tex ~/Documents/$(compute_folder_name foo-param)/subfolder1
$ follow

(Есть проблемы, например, что повторное расширение этих значений может больше не соответствовать исходному расширению, которое имело место. Предположим compute_folder_name, это функция, которая увеличивает некоторую глобальную переменную.)

Kaz
источник
4
Вам не нужно eval. (Когда-либо.) Но хорошее замечание на проблемах последовательности расширения. Если вы упомянете о большей целесообразности расширения истории для использования evalздесь, это будет лучшим ответом на мой взгляд; Ни один из других на самом деле не объясняет, почему решение оригинального плаката не сработало.
Wildcard