Существует ли однострочник, позволяющий мне создавать каталог и одновременно перемещаться в него?

150

Я повторяю много:

mkdir longtitleproject
cd longtitleproject

Есть ли способ сделать это в одной строке, не повторяя имя каталога? Я здесь на башке.

methodofaction
источник
1
mkdir longtitleprojectтогдаcd !^
user262826
Также был рассмотрен на askubuntu.com/q/927463/295286 и askubuntu.com/q/249314/295286
Сергей Колодяжный

Ответы:

160

Там нет встроенной команды, но вы можете легко написать функцию, которая mkdirзатем вызывает cd:

mkcd () {
  mkdir "$1"
  cd "$1"
}

Поместите этот код в свой ~/.bashrcфайл (или ~/.kshrcдля пользователей ksh, или ~/.zshrcдля пользователей zsh). Он определяет функцию с именем mkcd. "$1"будет заменен аргументом функции при запуске.

Эта простая версия имеет несколько недостатков:

  • Вы не можете создать цепочку подкаталогов сразу. Исправлено: передать -pпараметр в mkdir. (Это может или не может быть желательным, так как это увеличивает риск того, что опечатка mkcd mydierctory/newsubостанется незамеченной, например , удачно создастся mydierctoryи mydierctory/newsubкогда вы намеревались создать newsubвнутри существующего mydirectory.)
  • Если аргумент начинается с, -но не просто -, то mkdirи cdбудет интерпретировать его как вариант. Если это просто -, то cdистолковать это значит $OLDPWD. Если за +ним следуют 0 или более цифр, то cdв zsh он будет интерпретироваться как индекс в стеке каталогов. Вы можете исправить первую проблему, но не две другие, передав --перед аргументом. Вы можете исправить все эти проблемы, добавив ./аргумент, если это относительный путь.
  • mkdirне следует CDPATH, но cdделает, поэтому, если вы установили CDPATHзначение, которое не начинается с .(по общему признанию, несколько необычной конфигурации), то cdвы можете перейти в каталог, отличный от только что созданного. Предварение ./относительных путей исправления этого (он вызывает CDPATHигнорироваться).
  • Если mkdirне удается, он пытается выполнить cd. Исправление: используйте &&для разделения двух команд.

Все еще довольно просто:

mkcd () {
  case "$1" in /*) :;; *) set -- "./$1";; esac
  mkdir -p "$1" && cd "$1"
}

Эта версия по-прежнему может cdпереместиться в каталог, отличный от того, который mkdirтолько что был создан в одном крайнем случае: если аргумент mkcdсодержит ..и проходит через символическую ссылку. Например, если текущий каталог является /tmp/hereи mylinkявляется символической ссылкой на /somewhere/else, то mkdir mylink/../fooсоздает, /somewhere/else/fooтогда как cd mylink/../fooизменяется на foo. Недостаточно искать символические ссылки в аргументе, поскольку оболочка также отслеживает символические ссылки в своем текущем каталоге, поэтому cd /tmp/mylink; mkdir ../foo; cd ../fooне переходит в новый каталог ( /somewhere/else/foo), а в /tmp/foo. Исправление для этого - позволить cdвстроенному разрешить ..сначала все компоненты пути (не имеет смысла использовать, foo/..еслиfooне существует, поэтому mkdirникогда не нужно видеть ..).

Мы приходим к этой надежной, хотя и немного кровавой версии:

mkcd () {
  case "$1" in
    */..|*/../) cd -- "$1";; # that doesn't make any sense unless the directory already exists
    /*/../*) (cd "${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd -- "$1";;
    /*) mkdir -p "$1" && cd "$1";;
    */../*) (cd "./${1%/../*}/.." && mkdir -p "./${1##*/../}") && cd "./$1";;
    ../*) (cd .. && mkdir -p "${1#.}") && cd "$1";;
    *) mkdir -p "./$1" && cd "./$1";;
  esac
}

(Упражнение: почему я использую подоболочку для первого cdзвонка?)

В случае сбоя mkdir я хочу быть уверенным, что текущий каталог не будет изменен. Возвращение с помощью cd - или $ OLDPWD недостаточно, если оболочка не имеет разрешения перейти в свой текущий каталог. Кроме того, вызов cd обновляет OLDPWD, поэтому мы хотим сделать это только один раз (или восстановить OLDPWD).


Существуют также менее специализированные способы не вводить слово из предыдущей строки:

  • Введите cd , затем Esc .(или Alt+ .), чтобы вставить последний аргумент из предыдущей команды.
  • cd !$выполняется cdпо последнему аргументу предыдущей команды.
  • Нажмите, Upчтобы вызвать предыдущую командную строку, затем отредактируйте ее, чтобы перейти mkdirв cd.
жилль
источник
Спасибо! Esc. мне кажется наиболее удобным, имеет ли последовательность клавиш какое-то особое значение?
methodofaction
Это просто последовательность Bash (и унаследованная от ksh, а также работающая в zsh) для «повторить последнее слово предыдущей команды». Я использую это довольно часто.
geekosaur
31
@Gilles Я начинаю думать, что аккаунт "Gilles" фактически используется группой экспертов. ;-)
Кит
@StephaneChazelas на /a/b/..//самом деле будет работать, но нет /a/b/../c. Исправлена. Я поставил вопрос перед более широкой аудиторией.
Жиль
1
mkcd() { mkdir -p "$1" && cd "$1"; }Кажется, не проблема в (мой случай) Zsh. mkdir -p /var/tmp/somewhere/else /tmp/here; cd /tmp/here; ln -s /var/tmp/somewhere/else mylink; mkdir -p mylink/../foo && cd mylink/../foo; pwd(включает в себя настройки и) отображает /tmp/here/fooто, что было создано (и что я ожидал). bashошибочно создает и изменяет /var/tmp/somewhere/foo.
Адам Кац
134

Это тот вкладыш, который вам нужен. Никаких других настроек не требуется:

mkdir longtitleproject && cd $_

$_Переменная, в Баш, это последний аргумент , который в предыдущей команде. В этом случае имя каталога, который вы только что создали. Как объяснено в man bash:

_         At  shell  startup,  set to the absolute pathname used to invoke
          the shell or shell script being executed as passed in the  envi
          ronment  or  argument  list.   Subsequently, expands to the last
          argument to the previous command, after expansion.  Also set  to
          the  full  pathname  used  to  invoke  each command executed and
          placed in the environment exported to that command.  When check
          ing  mail,  this  parameter holds the name of the mail file cur
          rently being checked."$_" is the last argument of the previous command.

Используется cd $_для получения последнего аргумента предыдущей команды, а не cd !$потому, что cd !$дает последний аргумент предыдущей команды в истории оболочки :

cd ~/
mkdir folder && cd !$

вы в конечном итоге домой (или ~ /)

cd ~/
mkdir newfolder && cd $_

Вы попадаете в новую папку под домом !! (или ~ / newfolder)

Хесус Каррера
источник
23
Почему на Земле это один не принят ответ
JSmyth
1
@JSmyth Я согласен, это однострочник, который использует встроенные функции оболочки
sming
Я думаю, что ОП пытается избежать использования двух команд. Этот ответ (почти) так же действителен, как и сам mkdir foo && cd foo, что не удобно.
josemigallas
7
ОП запрашивает однострочник, который не требует повторения имени каталога, и это все
Хесус Каррера
Это традиционный однострочный текст, на который вы ссылаетесь или когда-либо видели, как другие используют его в документах / руководствах. Здесь на самом деле есть 3 идеальных ответа. Этот, один от @ jordan-harris, и выбранный ответ. Зависит от ваших настроек и предпочтений.
Уэйд
30

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

$ mkdir someDirectory<ENTER>
$ cd !$

где bash любезно заменяет !$последнее слово последней строки; т.е. длинное имя каталога, которое вы ввели.

Кроме того, завершение имени файла является вашим другом в таких ситуациях. Если ваш новый каталог был единственным файлом в папке, быстрый двойник TABдаст вам новый каталог без повторного ввода.

Хотя это здорово, что bash позволяет вам выполнять такие распространенные задачи, как и другие ответы, я думаю, что лучше изучить функции редактирования командной строки, которые предлагает bash, чтобы при работе на другом компьютере не пропустить синтаксический сахар, который предоставляют ваши пользовательские скрипты.

обкрадывать
источник
1
Есть ли хорошее место, чтобы узнать о самых важных причудах Bash, как этот?
dominicbri7
@ dominicbri7 Обычно относится к «редактированию командной строки bash». Поиск в Google также дает следующий результат как лучший результат web.mit.edu/gnu/doc/html/features_7.html Более конкретно,! $ - это пример Word Designator, см. gnu. org / программное обеспечение / bash / manual / bashref.html # Word-Designators
Роб
17

В соответствии с какими настройками вы сделали свой профиль оболочки для повышения производительности? Вот как я это делаю:

# make a directory and cd to it
mcd()
{
    test -d "$1" || mkdir "$1" && cd "$1"
}

это означает, что это также работает, если каталог уже существует.

Mikel
источник
4
-pВозможность MKDIR будет подавлять ошибки.
Гленн Джекман
1
mcd - это уже существующая команда. Хотя вы только что привели пример, я использовал его сам, так как это письмо короче, чем mkcd.
Дхармит
@ Дарм Шах: Какая команда существует mcd? Какой пакет или проект предоставляет эту команду?
Микель
2
mtools предоставляет команду mcd. На его странице руководства написано: «Команда mcd используется для изменения рабочего каталога mtools на диске MS-DOS».
Дхармит,
13

Если вы используете Oh My Zsh, есть команда take, которая делает именно это. Это будет выглядеть примерно так.

take myfolder

Я нашел это случайно. Я только что посмотрел, и он включен в этот чит-хит из вики Oh My Zsh GitHub. Это довольно полезная команда, и, видимо, ее очень легко создать самостоятельно.

Джордан Харрис
источник
1
Я никогда не знал о take:) Идеально! Кстати - iTerm2 с Oh My Zsh. Здесь на самом деле есть 3 идеальных ответа. Этот, один @ jesús-carrera, и выбранный ответ. Зависит от ваших настроек и предпочтений.
Уэйд
3

Или вы можете просто создать короткую переменную на лету и использовать ее дважды x = longproject ; mkdir $x ; cd $x- что, я признаю, все еще дольше, чем использование функции шеллскрипта :)

sakisk
источник
0

Вот небольшой вариант, который стоит упомянуть:

function mkdir() {
    local dir=$1
    command mkdir "$dir"  &&  cd "$dir"
}

Добавьте это к вашему, ~/.bash_profileи вы сможете использовать его mkdirкак обычно (как только вы это сделаете source), за исключением того, что теперь он будет запускать функцию выше, а не стандартную mkdirкоманду.

Обратите внимание, что это не проверяет ввод в соответствии с принятым ответом Жиля , но демонстрирует, как вы можете (эффективно) переопределить встроенные функции.

Из документов (слегка перефразируя):

command mkdir [args]работает mkdirс argsигнорированием любой именованной функции оболочки mkdir. Выполняются только встроенные команды оболочки или команды, найденные путем поиска в PATH. Если существует именованная функция оболочки ls, выполнение command lsвнутри функции выполнит внешнюю команду lsвместо рекурсивного вызова функции

Я считаю, что builtinдостигает аналогичного результата command.

архиватор ARJ
источник
Вы должны определенно цитировать$dir
Джефф Шаллер
@Джефф, согласен, но в принятом ответе есть все необходимые подтверждения. Я просто представляю использование commandв качестве альтернативы.
Arj
0

Добавление вспомогательной функции в BASH, ZSH или KSH

Создать mkcdкоманду для вашей среды в одну строку

echo -e 'mkcd() {\n mkdir -p "$1" && cd $_\n}' >> ~/.${0//-/}rc && . ~/.${0//-/}rc
следующий месяц
источник
-1

Просто автоматизировал вышеуказанные ответы и сделал одноразовый исполняемый скрипт:

fun='
mkcd ()
{
    mkdir -p -- "$1" && cd -P -- "$1"
}'

echo "$fun" >> ~/.bashrc

Просто скопируйте это в новый файл mkcd.shи запустите его только один раз в терминале bash mkcd.sh. Затем выполните source ~/.bashrcего, чтобы он работал в текущем сеансе.

После этого вы можете использовать mkcd some_dirдля создания и ввода непосредственно в этот каталог.

subtleseeker
источник
Вы предлагаете написать скрипт (в файле), единственной целью которого является добавление в ~/.bashrcфайл (с ответом, который уже был дан)? А как вы предлагаете создать этот mkcd.shскрипт? С редактором, возможно? Это похоже на большую работу, чем просто редактирование ~/.bashrc. Какое преимущество это имеет перед принятым ответом? ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... Это не удастся из-за цитирования вопросов, которые говорят мне, что вы даже сами не пробовали.
Скотт
Мне жаль говорить, но, как я уже писал в своем ответе, я использовал приведенные выше ответы. Это работает. Если не веришь мне, попробуй. И что касается того, чтобы не пытаться, я использовал весь свой день, чтобы писать такие скрипты на bash и python сегодня.
соискатель
Я попробовал то, что вы написали. Это не работает.
Скотт