BASH и поведение возврата каретки

11

У меня есть один быстрый вопрос.
Это нормально, что bash (я использую 4.4.11) не отображает строки / текст, который отделен / заканчивается простым \r?

Я был немного удивлен, увидев такое поведение:

$ a=$(printf "hello\ragain\rgeorge\r\n")
$ echo "$a"
george

Но текст «Привет снова» все еще там, как-то «спрятан»:

$ echo "$a" |od -w32 -t x1c
0000000  68  65  6c  6c  6f  0d  61  67  61  69  6e  0d  67  65  6f  72  67  65  0d  0a
          h   e   l   l   o  \r   a   g   a   i   n  \r   g   e   o   r   g   e  \r  \n

И как только мы просто поиграем с bash, это нормально ... Но разве это потенциальный риск для безопасности? Что если содержимое переменной «а» пришло из внешнего мира и содержит «плохие команды», а не просто привет?

Еще один тест, немного ненадежный на этот раз:

$ a=$(printf "ls;\rGeorge\n")
$ echo "$a"
George
$ eval "$a"
0                   awkprof.out       event-tester.log  helloworld.c      oneshot.sh         rightclick-tester.py  tmp                    uinput-simple.py
<directory listing appears with an error message at the end for command George>

Вообразите скрытое rmвместо скрытого ls.

То же поведение при использовании echo -e:

$ a=$(echo -e "ls;\rGeorge\r\n"); echo "$a"
George

Это я что-то не так делаю ...?

Георгий Василиу
источник

Ответы:

20

Вы echo "$a"печатаете «привет», затем возвращаетесь к началу строки (что и \rделает), печатаете «снова», возвращаетесь снова, печатаете «джордж», снова возвращаетесь и переходите к следующей строке ( \n). Это все совершенно нормально, но, как указывает Чепнер , это не имеет ничего общего с Bash: \rи \nинтерпретируется терминалом, а не Bash (именно поэтому вы получаете полный вывод, когда отправляете команду od).

Вы можете увидеть это лучше с

$ a=$(printf "hellooooo\r  again,\rgeorge\r\n")
$ echo "$a"

так как это оставит конец перезаписанного текста:

georgen,o

Вы не можете использовать это, чтобы скрыть команды, только, только их вывод (и только если вы можете быть уверены, что перезаписываете с достаточным количеством символов), если не используете, evalкак вы показываете (но использование, evalкак правило, не рекомендуется). Более опасным трюком является использование CSS для маскировки команд, предназначенных для копирования и вставки с веб-сайтов.

Стивен Китт
источник
Понятно, спасибо. Мне повезло / не повезло использовать последнее слово в моем тесте, способное полностью переписать предыдущие два слова.
Георгий
2
Обратите внимание, что это на самом деле не имеет ничего общего с bash; все зависит от терминала, как «отображать» возврат каретки или как отображать перезаписанные символы. Например, было бы совершенно правильно, чтобы терминал отображал -\r|что-то, напоминающее знак плюс, а не просто трубу.
chepner
@chepner Полезно знать! Спасибо, что поделился. Я думал, что это было просто поведение Баш.
Георгий
@ GeorgeVasiliou Нет, bashпросто записывает байты в файл; каждый, кто читает эти байты, должен их интерпретировать.
chepner
Nitpick:, printfкоторая является встроенной командой bash (хотя она также существует как отдельный исполняемый файл), интерпретирует \r(последовательность из двух байтов: 0x5cи 0x72и возвращает возврат каретки (один байт:) 0x0d. Затем, да, терминал интерпретирует байт 0x0dособым образом, но это не интерпретирует исходную строку \r.
Сюзанну Dupéron
6

В мире Unix возврат каретки (обычно кодируемый как \rв языках программирования) является ничем не примечательным управляющим символом. Вы можете иметь возврат каретки внутри строки текста, как и любой другой символ, кроме перевода строки (также называемого переводом строки ), который отмечает конец строки.

В частности, в скрипте bash возврат каретки является обычным символом, составляющим слово, таким как буквы и цифры. Любой специальный эффект возврата каретки происходит из терминала, а не из оболочки.

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

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

Если вы выводите ненадежный вывод, вам нужно удалить или удалить управляющие символы. Не только возврат кареты, но и некоторые другие, в частности, спасательный персонаж, который может вызывать всевозможные негативные последствия. См. Может ли «кошение» файла представлять потенциальную угрозу безопасности? и как избежать атак escape-последовательности в терминалах? больше по теме.

Жиль "ТАК - перестань быть злым"
источник
0

Вы можете просмотреть возврат каретки в переменной bash, используя printfфункцию с %qформатом.

$ TESTVAR="$(printf ' Version: 1 \r Build: 20180712 \r Test: 1324')"

$ printf %q $TESTVAR
Version:1$'\r'Build:20180712$'\r'Test:1324

Источники и дальнейшее чтение:

nuwandame
источник