Як виконати кілька команд, використовуючи один і той же аргумент?


16

Цікаво, чи можна робити ланцюгові дії в терміналі Ubuntu на зразок:

action 1 on objectA . then action 2 on objectA 

без того, щоб більше повторювати назву objectA.

Приклад:

touch file.js && openEditor "$1" 

чи щось подібне.


Існує маса способів зробити це, але це залежить від ваших потреб. Що таке об'єктA? файл ? Про які дії ми говоримо?
Сергій Колодяжний

спасибі, зазвичай файл ефективно, також може бути папка
HoCo_

3
Тут &буде відправлено команду "touch" на задній план. Якщо ви мали намір "відкрити редактор, якщо сенсор вдався", то &&замість цього ви хочете
glenn jackman

Чому ти натикаєшся на цю посаду? Ви вже отримали багато відповідей і навіть прийняли.
муру

Відповіді:


27

З розширенням історії bash ви можете звернутися до n-го слова поточного командного рядка, використовуючи, !#:nнаприклад,

$ touch foobar && ls -l !#:1
touch foobar && ls -l foobar
-rw-rw---- 1 steeldriver steeldriver 0 Jun 20 14:54 foobar

$ touch foo bar && ls -l !#:2
touch foo bar && ls -l bar
-rw-rw-r-- 1 steeldriver steeldriver 12 Jun 20 14:58 bar

Чи можу я запитати, яку версію bash ви використовуєте?
Сергій Колодяжний

@SergiyKolodyazhnyy цеGNU bash, version 4.3.48(1)-release
steeldriver

5
Ви також можете позначити діапазон слів :touch foo bar && ls -l !#:1-2
glenn jackman

1
@HoCo_ !персонаж вводить вираз розширення історії, коли ви знаходитесь в інтерактивній оболонці - він призначений для маніпуляцій з командним рядком під час введення, і вимикається всередині неінтерактивних сценаріїв
steeldriver

1
@HoCo_ в сценарії ви повинні знати, що аргумент випереджає час - так, наприклад, ви могли просто зробитиarg1=file.js; touch "$arg1" && openEditor "$arg1"
steeldriver

12

Існує зручний ярлик для загального випадку використання. У своєму прикладі ви робите:

$ touch file.js
$ openEditor <alt>+<.>

У другій команді хитрість полягає в тому, щоб записати openEditor(з пробілом після нього), а потім Alt+ .. Тут буде вставлено останній аргумент останньої команди, який є file.js. (Якщо це не працює з Altякихось причин, Escслід також працювати.)

Оскільки часто «об’єкт» справді є останнім аргументом попередньої команди, цим можна користуватися часто. Це легко запам'ятовується і швидко інтегрується у ваш набір інтуїтивно використаних ярликів оболонок.

Існує ціла купа речей, які ви можете зробити з цим, ось поглиблена стаття про можливості: /programming/4009412/how-to-use-arguments-from-previous-command .

Як бонус це буде працювати не тільки в bash, але і у всіх програмах, які використовують libreadline для обробки введення командного рядка.


2
Ви можете поєднати це з розрядним аргументом , наприклад , щоб отримати другий аргумент утримання Altі натисніть 2.(або Esc, 2, Esc, .), щоб отримати другу місце до останнього аргументу натисніть Alt+ -, тип 2і натисніть Alt+ .(або Esc, -2, Esc, .).
десерт

@dessert Що робити, якщо мені потрібно більше аргументів? Наприклад, я запускаю echo 1 2 3 4тоді я хочу 2і 3для наступної команди
wjandrea

@dessert Знайшов це сам! Вам просто потрібно набрати щось інше між ними, як пробіл. Щоб об'єднати їх, найпростіший спосіб - ввести простір, а потім назад.
wjandrea

1
@wjandrea утримання Altі тип 2., натисніть пробіл, утримання Altі типу 3.- якщо ви хочете , діапазон, використання розкриття історії: !!:2-3.
десерт

9

Що стосується інтерактивної оболонки bashта оболонки сценарію dash, ви можете використовувати $_для згадування останнього аргументу останньої команди .

$ echo "Hello World"; echo same "$_"
Hello World
same Hello World

csh і tcsh мають посилання на історію, спеціально для останнього слова команди ви можете використовувати !$, а для окремих аргументів - !:<index>:

~% echo foo bar
foo bar
~% echo !$
echo bar
bar

% echo bar baz
bar baz
% echo !:1
echo bar
bar

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

$ foo(){ echo "$@"; stat --print="%F\n" "$@";}
$ foo testdir
testdir
directory

1
Я хотів би лише зазначити, що це $_працює трохи інакше, ніж те !#:n, що остання розширюється перед збереженням команди в історії. Тож повернення в історію все одно показувало б команду з, $_тоді як !#:nбуло б замінено її фактичним значенням. У обох є свої плюси і мінуси.
Dan

3
Також, як завжди, $_слід сказати, оскільки в іншому випадку він розщеплюється і глобалізується, як і все. (Ми просто цього не бачимо, оскільки echoоб'єднує свої аргументи в єдиний пробіл.) Але, наприклад touch "hello there"; ls -l $_ , не вийде.
ilkkachu

1
@Dan Я думаю, що найбільшим профі $_є те, що він портативний. Зрештою, !#:nспецифічний для баш.
Сергій Колодяжний

3

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

Краще - перемогти цикл над усіма необхідними командами, використовуючи відповідний змінний:

$ for c in touch gedit; do $c foo.txt; done

Проблема в цілому полягає в тому, що Bash не робить аборт, коли виникає збій, тобто це насправді веде себе, як touch foo.txt; gedit foo.txtзамість того, щоб зв'язати з собою &&. Отже, щоб бути безпечним, ви можете додати break:

$ for c in touch gedit; do $c foo.txt || break; done

1

Готуючи однолінійку, я іноді присвоюю свою повторну річ змінній оболонки, яку я використовую кілька разів у команді. Я можу згадати та відредагувати його, щоб використовувати інший аргумент зі стрілкою вгору, керування + a, управління + стрілка праворуч, щоб отримати курсор близько до t=.

t=testloop; asm-link -d "$t.asm" && perf stat -r2 ./"$t"

Зауважте, що це полегшує приєднання до розширення чи зміни назви.

Також зауважте, що мені потрібно ;після призначення змінної, тому що він var=value cmdпросто встановлює це як змінну середовища для цієї команди, і не впливає на контекст оболонки.

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