Не можете використовувати! $ У сценарії?


11

Просто цікаво, чому це не працює

#!/bin/bash 

ls /bin
ls !$

Я розрахований на запуск ls /binдвічі, але другий викликає помилки, оскільки їх !$не інтерпретували

Я щось пропустив, або !$працював лише в командному рядку?

Не вдалося знайти відповідну частину в man bash(на mac)


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

Відповіді:


26

Історія та розширення історії відключені за замовчуванням, коли оболонка працює неінтерактивно.

Тобі потрібно:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

або:

SHELLOPTS=history:histexpand bash script.sh

це вплине на всі екземпляри bash, які script.shможуть працювати.


9
обережно з SHELLOPTS, це вплине на те, bashщо працює script.sh, але також і на всі інші bashекземпляри, які script.shможуть з часом працювати (як і інші bashсценарії ...).
Стефан Шазелас

І це не вплине на будь-який інший bash екземпляр, який запускає ваш сценарій.
Blacklight Shining

Я думаю, що ця відповідь покращиться, якби коментар @ StéphaneChazelas був відредагований у ній.
Оліфант - відновити Моніку

7

Здоровим було б зробити

ls /bin
ls $_

або

set ls /bin
$*
$*

або

c='ls /bin'
$c
$c

Застереження: варто пам’ятати, що кожен із них має деякі підводні камені. Рішення $ _ фіксує лише останній єдиний аргумент: так ls foo barвийде $ _, що містить просто bar. Один з допомогою setскасує аргументи ( $1, $2і т.д.). І все це, як написано, буде спрацьовувати, але коли їх узагальнити до складніших команд (де втеча і пробіл має значення), ви можете зіткнутися з деякими труднощами. Наприклад: ls 'foo bar'(де аргумент єдиного імені шляху foo barмістить два або більше пробілів або будь-які інші символи пробілу) в жодному з цих прикладів не поводиться правильно. Для обходу цих випадків може знадобитися правильне втеча (можливо, поєднане з evalкомандою) або використання "$@"замість цього $*.


1
+1 для відповіді, яка є портативною і не зловживає башизмом, призначеним для полегшення інтерактивного використання. (В бік бажання Баша до інтерактивного розгортання знаків оклику в налаштуваннях за замовчуванням - це те, що я вважаю протиінтуїтивним як користувач інших оболонок, і контрпродуктивне, тому що воно мене завжди накручує, коли я намагаюся виконати якусь складну команду оболонки).
mtraceur

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

@mtraceur: це не портативно, працювати лише в bash, zsh, ksh (якщо дві команди не в одному рядку). Працюйте в тирі, mksh лише тоді, коли інтерактивний
cuonglm

@cuongim: Вибачте, я був, мабуть, занадто недбало загальним. $_Спосіб не є портативним, ви маєте рацію. setПідхід працює в неінтерактивному тире, і з ${1+"$@"}(плюс ЗШ глобального псевдоніма) трюк повинна бути загальним, хоча я смутно пам'ятаю , що setє історія , не будучи абсолютно портативним з деякими (старими?) Оболонки. evalНаскільки я знаю, підхід "визначити-мінливу-утримування-команду-і-потім-еваль-", особливо з використанням правильного втечі та фактичної команди, є цілком портативним.
mtraceur
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.