Як я можу скласти власні "команди оболонки" (наприклад, mkdir / cd combo)?


41

Я не можу сказати, скільки разів я хотів отримати команду, яка б і створила каталог, і перейшла до цього каталогу. В основному, я хотів би еквівалент наступного:

mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path

але потрібно лише набрати /arbitrarily/long/pathодин раз, щось на зразок:

mk-cd /arbitrarily/long/path

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

#!/bin/bash
mkdir $1
cd $1
export PWD=$PWD

Як я міг би зробити цю роботу?


12
З cd, ви обрали окремий випадок вже з самого початку. : D
Даніель Б

2
Не зовсім те, що я шукав, але надзвичайно крута cdінформація (повернення до попереднього каталогу з використанням cd -, використанням pushdта popdпідтримкою "стека" каталогів): superuser.com/questions/324512/…
Крістофер Боттомс

8
Ви можете ввести mkdir -p /very/long/path, потім використовувати cd, пробіл, а потім натисніть Alt +, .щоб повторити останній аргумент, тобто ім’я dir.
чороба

2
Не відповідь, просто коментар, подібний до @ choroba's: Ви також можете використовувати mkdir -p /very/long/path; cd !#:2. Рядок !#:2розшириться до аргументу nr. 2 (тобто третій аргумент /very/long/path, оскільки підрахунок починається з нуля).
Інго Блешшмідт

3
@IngoBlechschmidt, ще простіше, оскільки це останній аргумент останньої команди, яку можна просто використовувати !$. Я використовую цей фокус постійно, хоча з розширенням історії можна зробити набагато більше .
Wildcard

Відповіді:


92

Найпростіший спосіб - використовувати функцію оболонки:

mkcd() {
    mkdir -p -- "$1" && cd -- "$1"
}

Помістіть його у свій .bashrcфайл, щоб він став доступним вам як і інша команда оболонки.

Причина, по якій він не працює як зовнішній скрипт, - це cdзміна поточного каталогу запущеного сценарію, але не впливає на викликає. Це за дизайном! Кожен процес має свій власний робочий каталог, який успадковується його дітьми, але навпаки це неможливо.

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

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

-pПараметр , який використовується з mkdirтам , щоб сказати цю утиліту , щоб створити відсутній каталог , який є частиною повного шляху імені каталогу , переданим в якості аргументу. Одним з побічних ефектів є те, що якщо ви попросите створити вже існуючий каталог, mkcdфункція не вийде з ладу, і ви опинитеся в цьому каталозі. Це може вважатися проблемою чи особливістю. У першому випадку функцію можна змінити, наприклад, таким чином, який просто попереджає користувача:

mkcd() {
    if [ -d "$1" ]; then
        printf "mkcd: warning, \"%s\" already exists\n" "$1"
    else
        mkdir -p "$1" 
    fi && cd "$1"
}

Без -pваріанту поведінка початкової функції була б дуже різною.

Якщо каталог, який містить каталог для створення, вже не існує, mkdirне працює функція.

Якщо створений каталог вже існує, він також mkdirне працює і cdне викликається.

Нарешті, зауважте, що налаштування / експорт PWDбезглуздий, оскільки оболонка вже робить це внутрішньо.

Редагувати: Я додав --опцію обом командам для функції, щоб дозволити ім'я каталогу, починаючи з тире.


5
Також слід додати, що ця команда не стане постійно доступною, якщо вона не буде додана до ~/.bashrcбудь-якого іншого сценарію ініціалізації.
AFH

Чи немає способу в bash зробити еквівалент tcsh alias mk-cd 'mkdir -p \!:1; cd \!:1'без функції? Чи, можливо, я повинен почати думати про функції bash, як про розширені псевдоніми?
Томас Падрон-Маккарті

@ ThomasPadron-McCarthy Цей cshмеханізм передачі аргументів не реалізований з псевдонімами стилю Bour. Функції - це справді шлях, будучи значно гнучкішим.
jlliagre

@ ThomasPadron-McCarthy - Можливо, ви хочете переглянути цю відповідь , яка дає досить непростий механізм доступу до параметрів, переданих на псевдонім (у визначенні bar). Іншим варіантом було б використання history 1, як в alias mk-cd='args="$(history 1)" && args="${args#*mk-cd\ }" && mkdir -p "$args" && cd'- це добре працює на прикладі запитувача, але не є загальним рішенням, оскільки будь-які інші команди в тому ж рядку (наприклад, трубопровід виводу) спричинить його збій.
AFH

3
@ ThomasPadron-McCarthy Ви повинні почати думати про псевдоніми tcsh, як про обмежені функції.
Жил "ТАК - перестань бути злим"

32

Я хотів би додати альтернативне рішення.

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

. mk-cd /arbitrarily/long/path

Якщо ви робите це, exportу сценарії це зайве. Ви можете обійти введення тексту .за допомогою alias:

alias mk-cd='. mk-cd'

Причина цього працює в тому, що сценарій зазвичай працює в підколонці, тому його середовище втрачається після завершення, але команда .(або source) змушує його запускатись у поточній оболонці.

Цей прийом може бути корисним для командних послідовностей, які занадто складні для функції або в процесі розробки і часто редагуються: після aliasвведення в .bash_aliasesнього сценарій можна редагувати за бажанням без повторної ініціалізації.

Зверніть увагу на наступне:

Якщо ви пишете скрипт, який повинен бути викликаний командою ./ source, є два способи переконатися в цьому: -

  1. Чомусь скрипт, на який посилається ./ sourceне потребує виконання, не слід виконувати його, тому просто видаліть цей дозвіл, і сценарій або не буде знайдений у "$ PATH", або дасть помилку дозволу, якщо буде викликано явний шлях.

  2. Як варіант, наступний трюк може бути використаний на чолі сценарію:

bind |& read && { echo 'Must be run from "." or "source" command'; exit 1; }

Це працює, тому що в підрозділі надсилається bindпопередження, хоча немає статусу помилки: отже, readвін використовується для введення помилки без введення даних.


Дякуємо за інформацію про .. Я робив . .bashrcнезліченну кількість разів, але не знав, що саме .робить. Це схоже на export?
cst1992

2
@ cst1992 - Ні, команди абсолютно різні: export varкопіює внутрішню змінну varв середовище, де вона успадковується та імпортується як змінна в будь-яку підколон, але це не впливає на батьківську оболонку. Зазвичай для запуску скрипту створюється підзагін, і всі його зміни (включаючи експортовані змінні) втрачаються після його завершення. Для того, щоб скрипт встановив змінні в оболонці, він повинен запускатися в цій оболонці, і це робиться .командою: запустіть скрипт без створення під оболонки. Цікаво, що сценарії, які виконуються, .не мають дозволу виконання.
AFH

Дякуємо за інформацію. Я б наполягав на тому, щоб ви включили цю інформацію у свій пост. Це корисно, і, чесно кажучи, коментарі не гарантують, що вони будуть там завтра.
cst1992

@ cst1992 - я вирішив оригінальне запитання, але я не хочу чіпляти свою відповідь додатковими питаннями. Якщо ви шукали пояснення команд .та exportкоманд, заголовок цього питання не призведе до того, що ви очікуєте відповіді тут, тож я дозволю моїй відповіді так, як є, але дякую за ваш коментар.
AFH

+1 загалом, але особливо для псевдоніма. У мене є кілька сценаріїв, які потрібно знайти, і я завжди забуваю виконувати їх таким чином. Псевдонім про це добре піклується.
Джо

13

Не одна команда, але вам не доведеться повторно вводити весь шлях, який ви просто використовуєте !$(це останній аргумент з попередньої команди в історії оболонки).

Приклад:

mkdir -p /arbitrarily/long/path
cd !$

1

Створюючи псевдоніми . Дуже популярний спосіб створення власних команд.

Ви можете створити псевдонім на льоту:

alias myalias='mkdir -p /arbitrarily/long/path; cd /arbitrarily/long/path'

Це воно. Якщо ви хочете постійно зберігати цей псевдонім (а не лише поточний сеанс), тоді введіть цю команду в dotfile (зазвичай ~ / .bash_aliases або ~ / .bash_profile).


4
Оскільки довге ім'я каталогу жорстко кодоване, цей псевдонім не буде дуже корисним, якщо цей каталог регулярно не знищується в результаті якогось іншого процесу.
jlliagre

1

Крім того, що вже було запропоновано, я хотів би порекомендувати thefuck . Це рамка Python для впорядкування процесу вашої оболонки шляхом виправлення помилок. Натхненний цим твіт , все, що вам потрібно зробити, - це ввести налаштований псевдонім (за замовчуванням fuck), і він спробує виправити попередню команду. Одне з його виправлень поводиться так:

/etc $ cd somedir
bash: cd: No such file or directory
/etc $ fuck
mkdir somedir && cd somedir
/etc/somedir $ 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.