Продолжая серию заметок о менее известных функциях bash, покажу вам семь переменных, о которых вы могли не знать.

1) PROMPT_COMMAND


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

На самом деле многие сложные манипуляторы prompt используют эту переменную, чтобы выполнять команды для сбора информации, которая отображается в приглашении.

Попробуйте запустить это в новом шелле, и увидите, что произойдёт с сессией:

$ PROMPT_COMMAND='echo -n "writing the prompt at " && date'

2) HISTTIMEFORMAT


Если запустить history в консоли, вы получите список команд, ранее выполненных под вашей учётной записью.

$ HISTTIMEFORMAT='I ran this at: %d/%m/%y %T '

Как только установлена эта переменная, новые записи записывают время вместе с командой, поэтому выдача будет выглядеть так:

1871  I ran this at: 01/05/19 13:38:07 cat /etc/resolv.conf
1872  I ran this at: 01/05/19 13:38:19 curl bbc.co.uk
1873  I ran this at: 01/05/19 13:38:41 sudo vi /etc/resolv.conf
1874  I ran this at: 01/05/19 13:39:18 curl -vvv bbc.co.uk
1876  I ran this at: 01/05/19 13:39:25 sudo su -

Форматирование соответствует символам из man date.

3) CDPATH


Чтобы сэкономить время в командной строке, можете использовать эту переменную для изменения каталогов так же легко, как вы вызываете команды.

Как и PATH, переменная CDPATH представляет собой список путей, разделённых двоеточием. Когда вы запускаете команду cd с относительным путём (т. е. без слэша в начале), по умолчанию оболочка ищет в вашей локальной папке соответствующие имена. CDPATH будет искать в путях, которые вы дали для каталога, куда хотите перейти.

Если установить CDPATH таким образом:

$ CDPATH=/:/lib

а затем ввести:

$ cd /home
$ cd tmp

то вы всегда попадёте в /tmp независимо от того, где находитесь.

Однако осторожно, потому что если не указать в списке локальную (.) папку, то вы не сможете создать любую другую папку tmp и перейти к ней, как обычно:

$ cd /home
$ mkdir tmp
$ cd tmp
$ pwd
/tmp

Упс!

Это похоже на путаницу, которую я почувствовал, когда понял, что локальная папка не была включена в более знакомую переменную PATH… но вы должны сделать это в переменной PATH, потому что вас могут обмануть, запустив фейковую команду из какого-нибудь скачанного кода.

Моя устанавливается начальной точкой:

CDPATH=.:/space:/etc:/var/lib:/usr/share:/opt

4) SHLVL


Вы когда-нибудь задумывались, ввод exit выведет вас из текущей оболочки bash в другую «родительскую» оболочку или просто полностью закроет окно консоли?

Эта переменная отслеживает, насколько глубоко вы вложены в оболочку bash. Если создать новый терминал, то он установлен на 1:

$ echo $SHLVL
1

Затем, если запустить другой процесс оболочки, число увеличивается:

$ bash
$ echo $SHLVL
2

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

5) LINENO


Также для анализа текущего состояния и отладки полезна переменная LINENO, которая сообщает количество команд, выполненных в сеансе к настоящему моменту:

$ bash
$ echo $LINENO
1
$ echo $LINENO
2

Это чаще всего используется при отладке скриптов. Вставляя такие строки, как echo DEBUG:$LINENO, вы можете быстро определить, где в скрипте вы находитесь (или нет).

6) REPLY


Если, как я, вы обычно пишете такой код:

$ read input
echo do something with $input

то может стать сюрпризом, что не нужно вообще беспокоиться о создании переменной:

$ read
echo do something with $REPLY

Это делает то же самое.

7) TMOUT


Чтобы не оставаться на продакшн-серверах слишком долго в целях безопасности или случайно не запустить что-нибудь опасное в неправильном терминале, установка этой переменной действует как защита.

Если ничего не вводится в течение установленного количества секунд, происходит выход из оболочки.

То есть это альтернатива sleep 1 && exit:

$ TMOUT=1

Комментарии (32)


  1. Voiddancer
    13.05.2019 08:03

    Я плохой линуксоид если не знал ни про одну из этих возможностей?


    1. mickvav
      13.05.2019 08:43
      +1

      Нет. Вы просто не читали man bash. Оно вообще занятное — массивы там всякие, сокеты, хитрые подстановки переменных.


    1. Sirikid
      13.05.2019 09:42

      Возможно вы просто не используете баш, это, несомненно, правильный выбор.


      1. Voiddancer
        13.05.2019 10:19

        Использую, но там где надо что-то сложнее пары сравнений предпочитаю питон.


        1. khim
          13.05.2019 19:38
          +3

          Как человек знающий-таки bash (и даже эти переменные)… могу вас только поддержать.

          bash — это ужасная вещь. Он начала создаваться ещё в 70е, когда о безопасности никто не думал, а когда начали думать — то добавили костылей. Что при этом не удалось сделать — так это сделать так, чтобы простые методы были бы безопасны.

          В результате любую задачу в bash можно сделать 10 разными способами из коготорых 9 простых — на самом деле не всегда работают.

          Использовать язык, в котором такого количества мин нету где возможно — очень разумное решение…


    1. Zverik
      13.05.2019 15:22

      Хороший линуксоид — не тот, кто всё знает, а тот, кто каждый день учится :)


  1. mayorovp
    13.05.2019 09:17

    Это похоже на путаницу, которую я почувствовал, когда понял, что локальная папка не была включена в более знакомую переменную PATH… но вы должны сделать это в переменной PATH, потому что вас могут обмануть, запустив фейковую команду из какого-нибудь скачанного кода.

    Хотел я спросить на каком это вообще языке написано и зачем при переводе был искажен смысл, но когда я залез в оригинальную статью — там оказалась написана такая же чепуха.


    На всякий случай поясняю о чем тут на самом деле речь: нельзя добавлять. в PATH, поскольку из-за этого могут переопределиться базовые команды шелла, как случайно, так и намеренно из-за действий злоумышленника. Так, вызывая ls, хочется быть уверенным что это именно /bin/ls, а вовсе не ./ls


  1. anton19286
    13.05.2019 09:20
    -1

    семь переменных, десять ядов, эксперты назвали пять продуктов вызывающих пригорание.
    просить убавить кликбейтное давление смысла нет?
    как ощущать себя товаром и продолжать получать удовольствие?


    1. atomlib
      13.05.2019 10:14

      Радикально менять название невозможно, поскольку это перевод.

      Что не так с заголовком этого текста?

      Предположим, это была бы написанная с нуля статья. Какое бы вы предложили название для неё?


      1. anton19286
        13.05.2019 10:41
        -1

        Интереса ради погуглил clickbait bingo.
        Из четырех слов заголовка два оттуда.


        1. Voiddancer
          13.05.2019 11:06

          Так вы предложите альтернативу то.


          1. lagranzh
            13.05.2019 12:04

            о мало известных возможнoстях bash?


            1. Voiddancer
              13.05.2019 12:09

              Но вы не упомянули что речь про, так сказать, системные переменные bash.


              1. lagranzh
                13.05.2019 12:46
                -1

                А и не надо. Про это есть в статье. То что эти возможности контролируются переменными, уже подробности имплементации. я так думаю :)


            1. Evengard
              13.05.2019 13:41
              +1

              Вот это точно кликбейт, когда из заголовка не ясен смысл, и приходится открывать статью чтоб разобраться, при том что тема интересная. А так всё ясно и понятно. Нормальный заголовок.


  1. immaculate
    13.05.2019 15:50

    Я давно перешел на fish. Переучивание было немного утомительным. Некоторые вещи работают не так как в bash/zsh, и знания, за 20+ лет пробороздившие мозг, периодически приводят к попыткам написать как в bash.


    Но одна вещь, которая вымораживает и из-за которой нет ни малейшего желания возвращаться. bash теряет историю. Да, у них в ChangeLog как минимум однажды писали, что эта проблема исправлена. Нет, не исправлена. Какие бы настройки истории я не использовал, рано или поздно возникает ситуация, когда я набираю Ctrl-R ansible-, и не вижу ровным счетом ничего. А потом гляжу в историю, и вижу, что она в очередной раз обнулилась. Обычно это случается в самый неподходящий момент, когда ты пытаешься срочно что-то починить или задеплоить.


    За много лет регулярные полные и частичные потери истории так меня достали, что я поклялся никогда не использовать bash в интерактивном режиме. Скрипты продолжаю писать на нем, так как он есть в каждой системе по умолчанию, даже в Windows уже.


    1. red_andr
      13.05.2019 19:39
      +1

      Не всегда так просто можно поменять shell, зачастую есть корпоративный стандарт, а какой-нибудь fish вообще не установлен. История да, это проблема в bash. Я решил её для себя сохраняя в файл, можно даже после каждой команды используя упомянутый тут PROMPT_COMMAND. А потом ещё и делая бакап этих файлов. Так что, не обязательно утомительно переучиваться. Плохо это или хорошо, но bash есть везде. Ну почти везде, не считая совсем урезанных версий на контроллерах.


      1. vvzvlad
        13.05.2019 23:59
        +1

        Я решил её для себя сохраняя в файл, можно даже после каждой команды используя упомянутый тут PROMPT_COMMAND.

        А как?


        1. nad_oby
          14.05.2019 00:26

          У меня пока прижился вот такой вариант, немного сложный, но для меня работает.
          Тут синхронизируется история между всеми сессиями на хосте (это упрощённая версия, на самом деле синхронизируется история для всех сессий с одной домашней директорией, например хомяк на NFS)
          Последняя строка срабатывает при каждом логине это «очистка» истории от «мусора» и не обязательна.

          export HISTCONTROL=ignoreboth:erasedups
          export PROMPT_COMMAND="history -n; history -w; history -c; history -r"
          TMPFILE=$(mktemp); tac "${HISTFILE}" | sed -e 's/[[:space:]]*$//' | awk '!x[$0]++' | tac > "${TMPFILE}" ; cat "${TMPFILE}" > "${HISTFILE}" ; rm "${TMPFILE}"; unset TMPFILE
          


          1. vvzvlad
            14.05.2019 17:43

            У меня в PROMPT_COMMAND было, оказывается, добавлено «history -a», но все равно не работало — между разными сессиями не синхронизировалось. Попробовал заменить на ваш вариант.


    1. Aldrog
      13.05.2019 20:26

      Для меня оказалось проще перейти на zsh. В нём после настройки с история ведёт себя хорошо, есть фичи, которых в баше не хватает, а синтаксис после bash гораздо привычнее, чем у fish.


    1. netch80
      13.05.2019 23:16
      -1

      Хранение истории в bash (точнее, в общем readline) действительно ужасно.
      Это как раз то место, куда напрашивается применить sqlite :)


    1. Alatarum
      14.05.2019 09:22

      > он есть в каждой системе по умолчанию, даже в Windows уже.

      А вот это спорное утверждение. В бсд, например, по умолчанию нету, пока не вытянется с чем-нибудь по зависимостям. Более того, /bin/sh там ВНЕЗАПНО действительно указывает на sh.
      Но это ещё ладно, его, неожиданно, по дефолту нету в Убунте, а под его именем скрывается dash, который хоть и совместим с башем в большей части, но бывают сюрпризы (иначе откуда бы я узнал, что там на самом деле не баш?).
      Ну и да, в эмбеддед обычно бизибокс, который тоже не совсем баш.
      Вообще, ситуация с этими подменами маразмотична, ИМХО, а тема башизмов давно избита. Поэтому я лично никогда не буду использовать эти 'неожиданные' переменные, дабы не выстрелить себе в ногу. И вообще, писать предпочитаю на sh.
      PS: в интерактивной режиме баша ещё раздражает например, что по умолчанию стрелки вверх/вниз тупо листают историю, а pgup/pgdown работают не везде, и что ^W стирает весь путь целиком. Поэтому всю жизнь пользовался tcsh, zsh или fish.


  1. iig
    13.05.2019 15:51

    Почему неожиданных то? Редко используемых — возможно. Что неожиданного в том, что есть в man bash (даже то, что его до конца не читают — это ожидаемо ;))? Если переменная PROMPT_COMMAND указывает, какую команду использовать при отображении приглашения — это ожидаемо. Вот если бы эта переменная включала, к примеру, debug mode — это было бы действительно неожиданно.


  1. ogost
    13.05.2019 19:03
    +3

    10 лет на Линукс и с bash, а они продолжают меня удивлять. Спасибо за перевод, многое узнал впервые. Уж гораздо интереснее, чем типичные "n лайфхаков в командной строке", где в 100500-тый раз опишут что-то вроде Ctrl+R или "cd -"


    1. nick_gabpe
      13.05.2019 20:03
      +2

      Спасибо за cd -



      1. igorp1024
        14.05.2019 11:44

        (Уже не про bash) А есть ещё и git checkout -


        1. asm0dey
          15.05.2019 23:30

          И git merge -, что в паре с checkout вообще офигенно!


  1. nick_gabpe
    13.05.2019 20:01
    +1

    Не считаю себя крутым линуксоидом, но о трёх возможностях знал. Тут просто как повезёт: нужно будет — узнаешь, если не нужно будет, то и не будешь об этом знать. Хотя кому-то явно будет полезно.


  1. maxzhurkin
    13.05.2019 21:47
    +1

    CDPATH может испортить не только настроение, но и сборку средствами make, например


  1. Telmah
    13.05.2019 22:18

    autojump намного интереснее и приятнее CDPATH — и кстати использует описанный выше PROMPT_COMMAND