Как выполнить несколько команд, используя один и тот же аргумент?

16

Интересно, можно ли выполнять цепные действия в терминале Ubuntu, например:

action 1 on objectA . then action 2 on objectA 

без необходимости повторять имя объекта A больше.

Пример:

touch file.js && openEditor "$1" 

или что-то типа того.

HoCo_
источник
Есть много способов сделать это, но зависит от ваших потребностей. Что за объект? файл ? О каких действиях мы говорим?
Сергей Колодяжный
спасибо, как правило, файл эффективно, также может быть папка
HoCo_
3
Здесь &отправим команду «touch» на задний план. Если вы намеревались «открыть редактор, если касание &&
прошло
Почему вы наткнулись на этот пост? Вы уже получили много ответов и даже приняли один.
Муру

Ответы:

27

С помощью bash History Expansion вы можете ссылаться на 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
steeldriver
источник
Могу я спросить, какую версию bash вы используете?
Сергей Колодяжный
@SergiyKolodyazhnyy этоGNU bash, version 4.3.48(1)-release
Steeldriver
5
Вы также можете обозначить ряд слов :touch foo bar && ls -l !#:1-2
Гленн Джекман
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будет заменено ее фактическим значением. У обоих есть свои плюсы и минусы.
Дан
3
Также, как обычно, $_следует заключать в кавычки, так как в противном случае он разбивается и сжимается, как все остальное. (Мы просто не видим его здесь, поскольку echoобъединяем его аргументы с одним пробелом.) Но, например touch "hello there"; ls -l $_ , не будет работать.
ilkkachu
1
@ Дэн, я думаю, самый большой профессионал в $_том, что он портативный. В конце концов, !#:nэто специфично для bash.
Сергей Колодяжный
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
leftaroundabout
источник
1

При приготовлении однострочника я иногда назначаю свою повторяющуюся вещь переменной оболочки, которую я использую в команде несколько раз. Я могу вспомнить и отредактировать его, чтобы использовать другой аргумент со стрелкой вверх, control + a, control + стрелка вправо, чтобы приблизить курсор к t=.

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

Обратите внимание, что это облегчает привязку к расширению или изменению имени.

Также обратите внимание, что мне нужно ;после присвоения переменной, потому что var=value cmdпросто устанавливает это как переменную среды для этой команды, и не влияет на контекст оболочки.

Питер Кордес
источник