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


150

Мені здається, що я повторюю багато:

mkdir longtitleproject
cd longtitleproject

Чи існує спосіб зробити це в одному рядку без повторення імені каталогу? Я тут на басі.




1
mkdir longtitleprojectпотімcd !^
користувач262826

Відповіді:


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. мені здається найбільш зручним, чи має послідовність клавіш якесь особливе значення?
методофакція

Це просто послідовність Bash (і успадкована від ksh, а також працює в zsh) послідовності "повторити останнє слово попередньої команди". Я використовую його досить часто.
geekosaur

30
@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.
Адам Кац

133

Це одне вкладиш, який вам потрібен. Інший конфігурація не потрібна:

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 $_

ви опинитесь в новому папку вдома !! (або ~ / нова папка)


23
Чому на Землі ця відповідь не прийнята
JSmyth

1
@JSmyth Я погоджуюсь, це однолінійний апарат, який використовує вбудовану функцію оболонки
посміхається

Я думаю, що ОП намагається уникати використання двох команд. Ця відповідь (майже) настільки ж справедлива, як і робити mkdir foo && cd foo, що не зручно.
josemigallas

7
ОП просить однокласника, який не потребує повторення імені каталогу, і це все
Jesús Carrera

Це традиційний однокласник, про який ви посилаєтесь або бачили, як інші використовують у документах / навчальних посібниках. Тут є насправді 3 ідеальні відповіді. Цей, той, від @ jordan-harris, і обрана відповідь. Залежить від налаштувань та переваг.
Вейд

30

Мені ніколи б не прийшло в голову скриптувати цю поведінку, бо я ввожу наступне майже щогодини ...

$ mkdir someDirectory<ENTER>
$ cd !$

де bash люб’язно замінює !$останнє слово останнього рядка; тобто довге ім'я каталогу, яке ви ввели.

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

Хоча це здорово, що bash дозволяє складати такі загальні завдання, як це дає інші відповіді. Я думаю, що краще вивчити функції редагування командного рядка, які пропонує bash, щоб, працюючи на іншій машині, ви не пропускали синтаксичну цукор, який надають ваші користувацькі сценарії.


1
Чи є хороше місце, щоб дізнатися про найважливіші примхи баш, як ця?
dominicbri7

@ dominicbri7 Як правило, під "редагуванням командного рядка bash" Google Googling ж дає такі результати як головний результат web.mit.edu/gnu/doc/html/features_7.html Більш конкретно ,! $ є прикладом Word Designer, див. gnu. org / software / bash / manual / bashref.html # Word-Designators
Роб

17

Згідно з якими налаштуваннями у вашому профілі оболонки зробили продуктивність? , ось так я це роблю:

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

це означає, що він також працює, якщо каталог вже існує.


4
-pМожливість MKDIR буде придушувати помилки.
glenn jackman

1
mcd - це вже існуюча команда. Хоча ви щойно наводили приклад, я використовував його сам, оскільки це лист коротший, ніж mkcd.
Дхарміт

@Dharmit Shah: Що таке існуюча mcdкоманда? Який пакет або проект надає цю команду?
Мікель

2
mtools надає команду mcd. На його довідковій сторінці написано: "Команда mcd використовується для зміни робочого каталогу mtools на диску MS-DOS."
Дхарміт

13

Якщо ви використовуєте Oh My Zsh, є команда під назвою take, яка робить саме це. Це виглядало б приблизно так.

take myfolder

Я насправді знайшов цю випадково. Я щойно подивився, і він перерахований на цю шпаргалку з вікі Oh My Zsh GitHub. Це досить корисна команда, і, мабуть, дуже легко створити себе.


1
Я ніколи про це не знав take:) Чудово! btw - iTerm2 з Oh My Zsh. Тут є насправді 3 ідеальні відповіді. Цей, той, який подав @ jesús-carrera, і обрана відповідь. Залежить від налаштувань та переваг.
Вейд

3

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


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.


Ви обов'язково повинні цитувати$dir
Джефф Шаллер

@ Джеф, погодився, але у прийнятій відповіді є все підтвердження, яке потрібно. Я лише представляю використання commandяк альтернативу.
Арж

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для створення та введення безпосередньо в цей каталог.


Ви пропонуєте написати сценарій (у файл), єдиною метою якого є додавання до ~/.bashrcфайлу (з відповіддю, яка вже була надана)? І як ви пропонуєте створити цей mkcd.shсценарій? Мабуть, з редактором? Це виглядає як більше роботи, ніж просто редагування ~/.bashrc. Яку перевагу має це над прийнятою відповіддю? ………………………………………………………………………… PS Це не вдасться через проблеми котирування, що говорить мені, що ви навіть самі не пробували цього.
Скотт

Мені шкода, але так, як я писав у своїй відповіді, я використав наведені вище відповіді. Це справді працює. Якщо ви мені не вірите, спробуйте. А щодо того, щоб не намагатися, я сьогодні використовував цілий день, щоб писати такі сценарії в bash та python.
підпильник

Я спробував те, що ви написали. Це не працює.
Скотт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.