Как правильно экранировать восклицательные знаки в bash?

11

Сегодня меня поймали с поличным, когда я пытался закодировать в гольф генератор паролей для Twitter.

import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))

90 символов Так как это много свободного места, я решил поднять планку и сделать ее исполняемой тоже.

echo -e "#!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg

139 символов Хорошо, за исключением, очевидно, удушения bash на восклицательный знак.

badp@delta:~$ echo -e "#!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg
bash: !/usr/bin/python\nimport: event not found

Пеский восклицательный знак. «Давайте избежим этого», - подумал я! В конце концов, у меня есть один запасной персонаж.

echo -e "#\!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg

Очевидно ...

badp@delta:~$ echo -e "#\!/usr/bin/python\nimport string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))">pg;chmod +x pg;./pg
./pg: line 2: syntax error near unexpected token `('
./pg: line 2: `import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))'
badp@delta:~$ cat pg
#\!/usr/bin/python
import string as s,random;print ''.join(random.sample(s.letters+s.digits+s.punctuation,9))

Оставляя в стороне мой гольф-код asinine - я не могу этого объяснить.

При \!этом восклицательный знак был исключен, за исключением того, что на самом деле это не так, потому что \!он оставлен как есть, echoчтобы забрать.

\x21Вместо этого можно было бы использовать одно решение , но я не уверен, что это правильный способ избежать восклицательного знака в команде bash.

tl; dr: Как правильно избежать восклицательного знака в команде bash?

badp
источник
Кто-нибудь на самом деле использует !eventсинтаксис в первую очередь? Это всегда доставляло мне только неприятности.
Badp
Я использую его почти ежедневно (в течение большей части последних 20 лет) !:0 !$и !^экономлю так много времени и печатать.
Алекс Рош

Ответы:

7

Используйте одинарные кавычки:

echo -e '#!/usr/bin/python\nimport string as s,random;print "".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg

Правила !были как бы привиты к другим правилам цитирования позже (из csh). Они были очень полезны, когда в оболочках не было редактирования командной строки, но некоторые люди до сих пор используют их.

PS Так как вы пишете код для bash:

echo $'#!/usr/bin/python\nimport string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'>pg;chmod +x pg;./pg

Это работает на большинстве единиц:

echo python -c \''import string as s,random;print"".join(random.sample(s.letters+s.digits+s.punctuation,9))'\'>pg;chmod +x pg;./pg

(Не то, чтобы я понял, почему вы хотите создать скрипт или почему имя скрипта должно состоять из двух букв.)

Жиль "ТАК - прекрати быть злым"
источник
Не знал о $''. :) PS: это было попытка использовать этих запасных персонажей. У меня возникает чувство траты, когда я публикую твиты короче 140 символов.
Badp
@badp: поэтому постарайтесь, чтобы он генерировал запоминающиеся пароли. (Как и в pwgenпротив pwgen -s.)
Жиль "ТАК ... перестать быть злым"
Можно также использовать dadadodo для запоминающихся, но бессмысленных парольных фраз :)
badp
1

Я должен был погуглить, прежде чем я спросил.

Поскольку вы не зависите от bash для расширения переменных [..], вы можете вместо этого использовать одинарные кавычки. Строки в одинарных кавычках не раскрываются с помощью bash.

Хонк в ответ на Как избежать восклицательного знака?

badp
источник
1
Я не отмечаю этот ответ как принятый, потому что он отвечает только на этот конкретный случай. Как правило, вы не можете уйти без расширения.
Badp