Не используйте "!!" в баше

    Каждый раз, когда неофит открывает для себя возможности баша и решает про это написать, он обязательно всем рассказывает про удобный метод «повторить команду» с использованием "!!".

    Типа так:
    $ touch /test
    touch: cannot touch ‘/test’: Permission denied
    $ sudo !!
    sudo touch /test
    

    Типа, хэппи-энд.

    Я никогда такого не использовал, но не задумывался, «почему». Просто мне не нравилась эта идея.

    А сейчас я придумал простой контрпример, который у любого хорошего человека отобъёт любое желание играться с восклицательным знаком в любой форме.

    echo NO ROOT PLEASE
     echo do it with sudo
    sudo !!
    

    (просто скопипастите это пример в шелл)

    Пробел перед командой означает «не добавляй меня в хистори». И восклицательные знаки этому подчиняются.

    Вы всегда уверены, что у вас случайно нет пробела в начале командной строки? ∎

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 77

      +15
      Вывод: пишите скрипты для bash, сидите в интерактиве в zsh!

      А вообще если не следишь за тем, что пишешь то ССЗБ. И не важно на "!!" ты нарвёшься или ещё на какой функционал.
        0
        Во всём этом «пробел перед командой» самый странный и неприятный.

        Вообще, я бы за дизайн "!!", который раскрывается молча после нажатия enter, сильно бил бы. Если бы оно на нажатие "!!" меняло бы командную строку, это была бы куда менее ужасная и куда более полезная функция (как и все остальные! команды).
          +1
          Возможно. Но мб кто-то их использует для не-интерактивного shell'а…
            –1
            Ну либо хотябы спрашивало
              +6
              Я обычно курсором повторяю предыдущую команду и дописываю sudo. Мне кажется, что это по времени немногим больше.
                –6
                Всё же есть значительная часть людей, которые очень не любят тянуть руку к мышке, мне даже лень до TrackPoint'а руку сместить. Я и далеко не одинок.
                  +10
                  А зачем мышь? [стрелка-вверх][home]sudo [enter]
                    –7
                    Я отвечал на конкретный пост. Прежде чем умничать тут читайте всю ветку.

                    > Я обычно курсором повторяю предыдущую команду
                    > А зачем мышь?

                    Не находите противоречий?
                      +5
                      Простите, что вмешиваюсь, но курсор — это понятие более общее, чем «курсор мыши». В частности, стрелки на клавиатуре в постсоветской литературе называют «клавиши управления курсором».

                      А вот тот зелёный/чб/мигающий квадратик/палочка — это тоже курсор.
                        –6
                        Если речь идёт о курсоре, которым можно что либо выделить, то речь идёт либо о перемещении манипулятора типа «мышь»/TrackPoint/TouchPad, либо комбинации клавиш для перемещения курсора в мультиплексоре, например screen. Но в случае мультиплексора работы нужно совершить ещё больше.
                        А уж нажатие стрелки вверх на клавиатуре для гулянья по истории, уж ни как не входит в манипуляцию курсором.
                          +1
                          Если я в отсутствие любого sreen'а, в обычном баше с readline, набираю текст, а потом делаю ctrl-w, это манипуляция с курсором?
                        +1
                        Поискал тщательно, не нашёл. Я отвечал на конкретный комментарий, и чтение ветки никоим образом не меняет его смысла. А раз речь идёт о командной строке, то было бы логично предположить, что имеется в виду текстовый курсор, а не курсор мыши, о чем вам написали ниже. Так что прежде чем умничать, вспомните что с помощью текстового курсора тоже можно выделять текст. А тов. Meklon просто немного неточно сформулировал свою мысль, но почему-то её поняли все кроме вас.
                          +2
                          Виноват)) тяжёлое детство, DOS и командная строка) ну привык я стрелки курсором называть. Это было весьма распространённое название этого блока клавиш. А сейчас их по-другому называют?
                      +3
                      Ниже уже ответили) курсор клавиатуры)
                      +20
                      7 нажатий: <s> <u> <d> <o> <space> <!> <!>
                      7 нажатий: <↑> <Home> <s> <u> <d> <o> <space>

                      Бонус: с большей вероятностью можно заметить, что повторил какой-нибудь rm -rf / some/folder.
                        +12
                        Ещё не забываем, что нужно зажать Shift для <!>
                          –4
                          На многих ноутбуках кнопка Home запрятана очень далеко, а очень она требует нажатия Fn клавиши.
                          И количество нажатий не совсем правильно считать, так как нажать одну и ту же клавишу два раза гораздо быстрее, нежели нажимать две разные клавиши.
                          Лично мне удобнее не тянутся к стрелочке и home, а напечатать "!!". Но это лично мне.

                          rm -rf / some/folder у меня отсекает zsh — он разворачивает "!!" и я могу посмотреть полностью команду и убедиться, что там нет ничего страшного.
                            +8
                            На многих ноутбуках кнопка Home запрятана очень далеко

                            Именно поэтому для дописывания sudo я возвращаюсь в начало команды с помощью Ctrl+A. Оно всегда под рукой, не надо думать, где на текущей машине кнопка Home.
                              +2
                              Век живи — век учись. Спасибо огромное за Ctrl+a
                          +1
                          CTRL+p / ESC+. вам в помощь :)
                          0
                          Как всегда, zsh можно настроить и так, и так. Кстати, у меня команда, начинающаяся с пробела, удаляется из истории с помощью функции zshaddhistory (не помню, чем меня не устроила настройка HIST_IGNORE_SPACE). А вообще zsh имеет кучу способов удаления из истории:
                          • $HISTORY_IGNORE: переменная, содержащая шаблон, под который должна подпадать игнорируемая команда
                          • setopt HIST_IGNORE_SPACE: настройка, заставляющая игнорировать командную строку, начинающуюся с пробела или использующую обычный (есть ещё suffix и глобальные) alias, начинающийся с пробела
                          • setopt HIST_NO_FUNCTIONS и setopt HIST_NO_STORE — игнорируют командную строку, в которой есть определение функции или вызов fc
                          • zshaddhistory: если данная функция завершится с кодом 1, то строка не будет сохранена, а если 2, то она не будет сохранена в файле, но будет в памяти.
                          Во всех случаях вы можете один раз получить команду повторно, независимо от того, была ли она сохранена в файле или в памяти или не была сохранена ни там, ни там.
                            0
                            У меня zsh при нажаетии enter показывает всю команду с развернутым "!!" и только потом я могу нажать enter еще раз и команда выполнится.
                              –1
                              Это настройка HIST_VERIFY (кстати, оказывается в bash она тоже есть: habrahabr.ru/post/246375/#comment_8188087) и судя по man zshoptions по‐умолчанию она не включена (как и в bash, кстати). Только zsh всегда даёт вам редактировать ранее введённую команду, а bash — нет.
                          +10
                          (просто скопипастите это пример в шелл)

                          @[~]$ echo NO ROOT PLEASE
                          NO ROOT PLEASE
                          @[~]$  echo do it with sudo
                          do it with sudo
                          @[~]$ sudo !!
                          sudo  echo do it with sudo
                          Password:
                          

                          Почему? Потому что пропуск команд с пробелом вначале по умолчанию выключен в bash (хотя мейнтейнеры каких-нибудь дистрибутивив могут и включить).

                          P.S. Оказывается, хабрапарсер заменяет восклицательные знаки в количестве больше одного и предваряющие их пробельные символы тремя восклицательными знаками, смотрите:! (один),!!! (два),!!! (три),!!! (четыре),…
                            0
                            Кроме проблемы с пробелом, здесь кроется еще одна — сильная жесткая связь с предыдущей командой. При развитии скрипта может появится потребность что-то добавить между или перенести кусок из этого скрипта в другой и таким образом все поломать.

                            Похожая неприятность поджидает пользователей математических пакетов — там тоже обычно есть подстановка для интерактивного режима, обозначающая «последний ответ» — в maxima это %, в maple — ans и так далее.
                              +2
                              Не думаю, что много людей это использует в скриптах, это для интерактивного режима сделано. Тем более, что (из «man bash»):
                              … This feature is enabled by default for interactive shells, and can be disabled using the +H option to the set builtin command (see SHELL BUILTIN COMMANDS below). Non-interactive shells do not perform history expansion by default.
                              +19
                              В каждом инструменте можно найти возможность отстрелить себе ногу, это не повод не пользоваться фичами этого инструмента
                                +3
                                А есть вообще прецеденты использования "!!" в скриптах, а не в интерактивном сеансе?
                                • UFO just landed and posted this here
                                    +3
                                    У меня по двойному нажатию Esc к предыдущей комманде добавляется “sudo”. Дальше я решаю жмякать Enter или нет.
                                    Стоит oh-my-zsh
                                      0
                                      А как это включить?
                                        +1
                                        В .zshrc plugins= добавить sudo в списке расширений для oh-my-zsh.
                                        0
                                        Спасибо огромное!(!)
                                        –1
                                        На вкус, запах и цвет все фломастеры разные.
                                        Любой пробел с какой либо фичей может восприниматься в определенной ситуации как недоработка. Это просто говорит об отсуствии большего опыта, а пост на невратический срыв.

                                        Хотя в вашем посте и рациональное звено — не стоит злоупотреблять чем-либо. Умеренность — это задаток равновесия.
                                          –1
                                          А большой опыт — это сколько? Десять лет эксплуатации? 15? 20? Про диагнозы по переписке я тактично умолчу.
                                            0
                                            Больший опыт, это когда после одного просмотра кода сразу понятно почему он не правильно функуионирует. Это когда вы на автомате помните, что пробелы оставлять не нужно, п текст просматриваете с режимом покпза спецсимволов,
                                              –2
                                              А. То есть идеальный сисадмин не делает ошибок. Так же как и идеальный программист.

                                              Ясно, идея понятна, спасибо.
                                                0
                                                Нет. Ничего вам не понятно. И сисадмин и программист с каждым разом делают меньше ошибок, создавая код, способный работать с первого раза.
                                                  –1
                                                  Круто. То есть чудаки с тестами и лузеры с CVE, так?
                                                    0
                                                    Тесты логично создавать, когда код содержит множество входнях параметров и зависимостей и не возможно при любом изменении быть уверенным, что изменения не привели к коррекции ранее правильно работающих участков обработки.
                                                      0
                                                      Тесты логично создавать для любого кода, который будет изменяться. То есть для любого кода, который будет использоваться больше одного раза.
                                                        +1
                                                        Спасибо, это очень важно.

                                                        Теперь к первоначальному тезису о том, что чем опытнее сисадмин или программист, тем меньше он ошибок делает. Рост числа CVE говорит о том, что или программисты становятся всё хуже, или ваша идея не верна.

                                                        Hint: если бы сисадмин всю свою жизнь делал одно и то же, то да. А чаще всего есть такая штука, как рост квалификации и специализация (не говоря уже про дрифт технологий).
                                            +10
                                            shopt -s histverify в .bash_profile, и команда из истории будет не сразу выполнятся, а просто выводиться.
                                              +1
                                              А вот за это спасибо. Не знал.
                                              0
                                              Никогда не пользовался "!!", но разве (по крайней мере в zsh) не для этого есть tab, который развернёт "!!" и позволит её просмотреть перед выполнением.
                                                0
                                                sudo спрашиваает пароль.

                                                !!! печатает полную команду перед её исполнением.
                                                  0
                                                  У меня судо проверяет ssh-ключ. Плюс, это происходит первый раз, а потом в течение нескольких минут судо минут судо идёт без авторизации.
                                                    0
                                                    Как настраивать? А то как-то тупо получается — сервер внутрь пустил без вопросов, а потом просить пароль.
                                                      0
                                                      Отдельный auth-модуль. Требует проброса ssh-агента.
                                                        0
                                                        Долго возиться? В принципе, уже сомневаюсь стоит ли заморачиваться ради одного пароля)
                                                          0
                                                          С пакетированием и правильным выкатыванием у нас заняло пару-тройку дней. Жизнь стала сильно краше, потому что топтать пароль по каждому чиху (на разных серверах — по новой и по новой) страшно задалбывает.
                                                            0
                                                            Ну, с моим десятком машин это не критично)
                                                              0
                                                              А теперь расскажете нам о вреде 'sudo -s'?

                                                              Audit trail не предлагать, можно удобно логировать с привязкой к пользователю.
                                                                +1
                                                                Зависит от ситуации. Если пользователи равноправны, а конфигурация управляется через git, то sudo -s используется преимущественно для диагностики. В условиях паучьего гнезда — любая пролетающая бабочка рушит кластер, это и так понятно.

                                                                ssh-ключи при судо просто защищают машину от «странных» вещей, проверяя, что пользователь всё ещё обладает ключом. При том, что у рута отключен логин, это позволяет быть уверенным, что команду запускает именно пользователь, а не забытый в чужом namespace'е tshark.
                                                                  0
                                                                  Логично, спасибо.
                                                              0
                                                              4 строчки в конфиг — пароль все еще будет спрашиваться первый раз, но потом 4 часа будет пускать без пароля.

                                                              P.S. если ip address сервера меняется пока сокет открыт, то придется руками удалить сокет — rm /tmp/ssh_mux_x_y_z

                                                              cat ~/.ssh/config
                                                              
                                                              Host *.my.servers.domain
                                                              	ControlMaster auto
                                                              	ControlPath /tmp/ssh_mux_%h_%p_%r
                                                              	ControlPersist 4h
                                                              
                                                                0
                                                                Это всё жестоко обламывается на злые наты, которые рвут idle коннекты куда непопадя, да и всякие штуки вроде «переткнуться между сетями» портят.
                                                                  0
                                                                  Это верно, но жить можно. Наты на самом деле не так сильно мешают, проброс портов так же замечательно работает.

                                                                  Что неработает так это escape sequence — (aka ~), что действительно раздражает, но не все люди это используют. В общем я считаю что попробовать очень просто, а решить нравится или нет уже каждый сам.
                                                                    0
                                                                    кипэлайвы, разве, не спасают?
                                                                      0
                                                                      От этого спасают. Зато если в сети потери пакетов, постоянный keepalive вгоняет tcp в такую депрессию, что поджатое окно делает жизнь почти невозможной (не говоря уже про удовольствие ждать, пока сначала keepalive просрётся да перешлётся, а потом уже свои пакетики слать).
                                                                        0
                                                                        В случае с потерей пакетов, я думаю, есть проблемы посерьёзней тормозного ssh.
                                                                        А вообще. я как-то работал с каналом, где задержка была от 2х секунд. Вспомнил всё, всё что умел в неинтерактивной консоли.
                                                                  0
                                                                  Вот тут писали как это можно относительно просто сделать через pam-ssh-agent-auth.

                                                                  Но иногда, хоть и не так секьюрно, но проще просто добавить в конце в ваш sudoers-файл для пользователей, заходящих с authorized_key, опцию NOPASSWD:
                                                                  # Allow members of group sudo to execute any command
                                                                  %sudo   ALL=(ALL:ALL) ALL
                                                                  # Allow admin user execute anything without password
                                                                  admin ALL=(ALL) NOPASSWD:ALL
                                                                  

                                                                  Нужно только помнить, что в этом случае не важно как и когда пользователь авторизовался (со всеми вытекающими), но если единственно возможно только через authorized_key, то почему нет…
                                                                    0
                                                                    Такой вариант плох, потому что забытый процесс после отключения пользователя по-прежнему может юзать sudo без пароля. В случае с проверкой ключа, если в screen'е или просто в bg кто-то что-то забыл, то оно автоматически теряет какие-либо привилегии.
                                                                      0
                                                                      Вы вероятно имеете ввиду второе… Ну я как-бы и писал, что оно не то что бы супер-метод.
                                                                      И потом, кто же страртует child-«демоны» с tty? А без оного думается мы получим в дочернем процессе, что то типа:
                                                                      sudo: sorry, you must have a tty to run sudo
                                                                      

                                                                        0
                                                                        Ну, получить/сделать tty не так уж и трудно. Кроме того, речь про самые разные штуки, включая «в скрине» (где tty есть) и т.д.
                                                                          –1
                                                                          Defaults requiretty
                                                                          вот такую строчку убрать и будет счастье.
                                                            0
                                                            Странно. У меня в bash в Gnome Terminal и с пробелом команда попадает в историю. На удаленном серваке по SSH не попадает. Это настраивается?
                                                              +1
                                                              В bash же есть HISTCONTROL и, настраивая ignorespace, нужно понимать последствия.
                                                                –2
                                                                В zsh есть множество вариантов удаления истории. Но вы всегда можете один раз воспользоваться предыдущей введённой строкой, даже если она и не сохранится потом в истории. В том числе это работает и с !!.
                                                                  +1
                                                                  Это звучит, как что-то не правильное. Указание «не сохранять» не работает для предыдущей команды?
                                                                    0
                                                                    Оно работает. Просто есть три места для сохранения: файл, структура в памяти и специальное место, где сохраняется предыдущая строка. В зависимости от настроек вы можете не сохранить строку в памяти и файле либо не сохранить в файле. Но вы не можете не сохранить (точнее можете, но с использованием ряда хаков) предыдущую команду в этом специальном месте. Очень удобно и совершенно правильно: или вам нравится перепечатывать «несохраняемую» строку на каждой ошибке (копирование — вставка не всегда вариант и всегда медленнее стрелочки вверх или эквивалента)?

                                                                    Команда станет недоступна из истории, как только вы введёте следующую. С моими функциями zshaddhistory и собственным widget'om accept-line (отвечает за исполнение введённой строки, у меня на нём лежит исполнение команд с нестандартным синтаксисом) команда исчезает даже если просто «отправить на исполнение» пустую строку, но вообще-то вам нужно ввести что-то непустое.
                                                                0
                                                                Мода на!!! началась же не так давно?

                                                                Да какого лешего оно перед blockquote вставляет ещё один восклицательный знак?
                                                                  0
                                                                  И никто не вспомнил про bashrc?
                                                                  sed -i 's/HISTCONTROL=ignorespace//g' .bashrc
                                                                  

                                                                  (Для новичков: это удалит настройку, отвечающую за игнорирование пробела в истории баша из вашего конфига, нужно только учитывать, что $HISTCONTROL может содержать ещё другие опции, отделённые :.)
                                                                    0
                                                                    Парой коментов выше вижу, надо лучше высыпаться. :)
                                                                    +1
                                                                    по тому же принципу все вписывают
                                                                    alias rm='rm -i'
                                                                    А мне приходится либо -f добавлять, либо алиас удалять…
                                                                    всё опасно в том или ином виде. В данном случае, вероятность нарваться на пробел, в целом, достаточно низка. А если реализуется часто, можно отключить опцией.
                                                                      0
                                                                      Вы не поняли. В данном примере вы не «нарываетесь» на пробел. Вы намеренно ставите его там, чтобы строка после пробела не сохранилась в истории. Bash здесь реализует логичное, но неудобное поведение — такую строку переиспользовать средствами bash нельзя никак.
                                                                        0
                                                                        А, нет, автор в конце считает, что пробел там может быть поставлен случайно. Тогда присоединюсь: вероятность нарваться на пробел низкая.

                                                                    Only users with full accounts can post comments. Log in, please.