bash: включая как\n, так и двойные кавычки в строковой переменной [duplicate]

Наконец, ожидание закончилось с SQL Server 2016. Они ввели функцию строки Split, STRING_SPLIT :

select OtherID, cs.Value --SplitData
from yourtable
cross apply STRING_SPLIT (Data, ',') cs

Все остальные методы разделения строки например, XML, таблица Tally, while loop и т. д. были сдуты этой функцией STRING_SPLIT.

Вот отличная статья с сопоставлением производительности: Сюрпризы производительности и предположения: STRING_SPLIT .

Для более старых версий использование таблицы tally table здесь - это одна функция разделения строк (наилучший возможный подход)

CREATE FUNCTION [dbo].[DelimitedSplit8K]
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
     -- enough to cover NVARCHAR(4000)
  WITH E1(N) AS (
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
                 SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT 1 UNION ALL
                 SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
                ),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
                 SELECT s.N1,
                        ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
                   FROM cteStart s
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;

Ссылка на Tally OH! Улучшенная функция SQL 8K «CSV Splitter»

213
задан Juan A. Navarro 5 June 2015 в 07:20
поделиться

9 ответов

Решение состоит в использовании $'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.
236
ответ дан TRiG 25 August 2018 в 09:17
поделиться

В моей системе (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"
0
ответ дан Alexey 25 August 2018 в 09:17
поделиться

A $ перед одинарными кавычками «...\n ...» следующим образом, однако двойные кавычки не работают.

$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
2
ответ дан caot 25 August 2018 в 09:17
поделиться

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

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

$STR2
EOF
)
echo "$NEWSTR"

Мне было легче форматировать тексты.

3
ответ дан Jason 25 August 2018 в 09:17
поделиться

Эхо так девяносто и настолько чревато опасностями, что его использование должно привести к дампам ядра не менее 4 ГБ. Серьезно, проблемы эха были причиной того, что процесс стандартизации 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, все становится аккуратно напечатанной и полностью переносимой поддержкой для escape-последовательностей C. Все, пожалуйста, используйте printf сейчас и никогда не оглядывайтесь назад.

117
ответ дан Jens 25 August 2018 в 09:17
поделиться

Я обнаружил, что -e флаг элегантный и прямой

STR="Hello\nWorld" echo -e $STR #outputs Hello World

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

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

7
ответ дан Simon Ndunda 25 August 2018 в 09:17
поделиться

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

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

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

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

#!/bin/sh
string="Hello
World"
echo "$string"  # note double quotes!
19
ответ дан tripleee 25 August 2018 в 09:17
поделиться
  1. Единственная простая альтернатива заключается в том, чтобы на самом деле ввести новую строку в переменную:
    $ STR='new
    line'
    $ printf '%s' "$STR"
    new
    line
    
    Да, это означает запись Enter, где это необходимо в коде.
  2. Существует несколько эквивалентов new line.
    \n           ### A common way to represent a new line character.
    \012         ### 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 'new\012line'          ### Valid in POSIX printf.
    printf 'new\x0Aline'       
    printf '%b' 'new\0012line'    ### 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
    
13
ответ дан user 25 August 2018 в 09:17
поделиться

То, что я сделал по другим ответам, было

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
37
ответ дан zvezda 25 August 2018 в 09:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: