Как я могу иметь строку в строку в SH?

этой

STR="HellonWorld"
echo $STR

производит как выход

HellonWorld

вместо

Hello
World

что мне делать, чтобы иметь новую строку в строке?

Примечание: этот вопрос не о Эхо. Я в курсе echo -e, но я ищу решение, которое позволяет передавать строку (которая включает новую строку) в качестве аргумента другое команды, которые не имеют аналогичной опции для интерпретации n'S, как новая строка.

10 ответов


решение заключается в использовании $'string', например:

$ STR=$'Hello\nWorld'
$ echo "$STR"
Hello
World

вот выдержка из страницы руководства Bash:

   Words of the form $'string' are treated specially.  The word expands to
   string, with backslash-escaped characters replaced as specified by  the
   ANSI  C  standard.  Backslash escape sequences, if present, are decoded
   as follows:
          \a     alert (bell)
          \b     backspace
          \e
          \E     an escape character
          \f     form feed
          \n     new line
          \r     carriage return
          \t     horizontal tab
          \v     vertical tab
          \     backslash
          \'     single quote
          \"     double quote
          \nnn   the eight-bit character whose value is  the  octal  value
                 nnn (one to three digits)
          \xHH   the  eight-bit  character  whose value is the hexadecimal
                 value HH (one or two hex digits)
          \cx    a control-x character

   The expanded result is single-quoted, as if the  dollar  sign  had  not
   been present.

   A double-quoted string preceded by a dollar sign ($"string") will cause
   the string to be translated according to the current  locale.   If  the
   current  locale  is  C  or  POSIX,  the dollar sign is ignored.  If the
   string is translated and replaced, the replacement is double-quoted.

Echo настолько девяносто и настолько чревато опасностями, что его использование должно привести к дампам ядра не менее 4 ГБ. Серьезно, проблемы echo были причиной того, что процесс стандартизации Unix наконец изобрел printf утилита, устраняющая все проблемы.

Итак, чтобы получить новую строку в строке:

FOO="hello
world"
BAR=$(printf "hello\nworld\n") # Alternative; note: final newline is deleted
printf '<%s>\n' "$FOO"
printf '<%s>\n' "$BAR"

там! Нет SYSV против BSD Echo madness, все аккуратно печатается и полностью переносится поддержка C escape-последовательностей. Все, пожалуйста, используйте printf теперь и никогда не оглядываться назад.


то, что я сделал, основываясь на других ответах, было

NEWLINE=$'\n'
my_var="__between eggs and bacon__"
echo "spam${NEWLINE}eggs${my_var}bacon${NEWLINE}knight"

# which outputs:
spam
eggs__between eggs and bacon__bacon
knight

проблема не в оболочке. Проблема на самом деле с echo сама команда и отсутствие двойных кавычек вокруг переменной интерполяции. Вы можете попробовать использовать echo -e но это не поддерживается на всех платформах, и одна из причин printf теперь рекомендуется для переносимости.

вы также можете попробовать вставить новую строку непосредственно в сценарий оболочки (если сценарий-это то, что вы пишете), чтобы он выглядел...

#!/bin/sh
echo "Hello
World"
#EOF

или эквивалентно

#!/bin/sh
string="Hello
World"
echo "$string"  # note double quotes!

  1. единственная простая альтернатива-фактически ввести новую строку в переменной:

    $ STR='new
    line'
    $ printf '%s' "$STR"
    new
    line
    

    Да, это значит писать Enter где это необходимо в коде.

  2. существует несколько эквивалентов new line символ.

    \n           ### A common way to represent a new line character.
    2         ### Octal value of a new line character.
    \x0A         ### Hexadecimal value of a new line character.
    

    но все они требуют "интерпретации" каким-то инструментом (POSIX printf):

    echo -e "new\nline"           ### on POSIX echo, `-e` is not required.
    printf 'new\nline'            ### Understood by POSIX printf.
    printf 'new2line'          ### Valid in POSIX printf.
    printf 'new\x0Aline'       
    printf '%b' 'new12line'    ### Valid in POSIX printf.
    

    и поэтому инструмент требуется для сборки строка с новой строкой:

    $ STR="$(printf 'new\nline')"
    $ printf '%s' "$STR"
    new
    line
    
  3. в некоторых оболочках последовательность $' является специальным расширением оболочки. Известно, что работает в ksh93, bash и zsh:

    $ STR=$'new\nline'
    
  4. конечно, более сложные решения также возможны:

    $ echo '6e65770a6c696e650a' | xxd -p -r
    new
    line
    

    или

    $ echo "new line" | sed 's/ \+/\n/g'
    new
    line
    

найти -e флаг элегантный и прямо вперед

STR="Hello\nWorld" echo -e $STR выходы# Hello World

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

indexes_diff=$(git diff index.yaml) echo "$indexes_diff"


Я не эксперт bash, но этот работал для меня:

STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1

$STR2
EOF
)
echo "$NEWSTR"

Я нашел это проще для форматирования текстов.


a $ прямо перед одинарными кавычками '...\северный... однако двойные кавычки не работают.

$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld

в моей системе (Ubuntu 17.10) ваш пример работает по желанию, как при вводе из командной строки (в sh) и при выполнении как sh сценарий:

[bash]§ sh
$ STR="Hello\nWorld"
$ echo $STR
Hello
World
$ exit
[bash]§ echo "STR=\"Hello\nWorld\"
> echo $STR" > test-str.sh
[bash]§ cat test-str.sh 
STR="Hello\nWorld"
echo $STR
[bash]§ sh test-str.sh 
Hello
World

Я думаю, это ответ на ваш вопрос: он просто работает. (Я не пытался выяснить детали, например, в какой именно момент замена символа новой строки на \n происходит sh).

однако я заметил, что этот же скрипт будет вести себя по-разному при выполнении С bash и печать Hello\nWorld вместо:

[bash]§ bash test-str.sh
Hello\nWorld

мне удалось получить желаемый результат с bash следующим образом:

[bash]§ STR="Hello
> World"
[bash]§ echo "$STR"

обратите внимание на двойные кавычки $STR. Это ведет себя одинаково, если сохранено и выполняется как bash сценарий.

следующее также дает желаемый результат:

[bash]§ echo "Hello
> World"

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

IFS="$(printf '\nx')"
IFS="${IFS%x}"

Bash (и, вероятно, другие оболочки) сожрать все конечные новые строки после замены команды, поэтому вам нужно закончить printf строка с символом перевода строки и удалить его после этого. Это также может легко стать проявляющаяся.

IFS="$(printf '\nx')" IFS="${IFS%x}"

Я знаю, что это два действия вместо одного, но мой отступ и переносимость ОКР at peace now :) Я изначально разработал это, чтобы иметь возможность разделить вывод только новой строки, и я закончил использование модификации, которая использует \r как завершающий символ. Это делает работу разделения новой строки даже для вывода dos, заканчивающегося на \r\n.

IFS="$(printf '\n\r')"