Наконец, ожидание закончилось с 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»
Решение состоит в использовании $'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.
В моей системе (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"
A $ перед одинарными кавычками «...\n ...» следующим образом, однако двойные кавычки не работают.
$ echo $'Hello\nWorld'
Hello
World
$ echo $"Hello\nWorld"
Hello\nWorld
Я не эксперт по bash, но этот работал для меня:
STR1="Hello"
STR2="World"
NEWSTR=$(cat << EOF
$STR1
$STR2
EOF
)
echo "$NEWSTR"
Мне было легче форматировать тексты.
Эхо так девяносто и настолько чревато опасностями, что его использование должно привести к дампам ядра не менее 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
сейчас и никогда не оглядывайтесь назад.
Я обнаружил, что -e
флаг элегантный и прямой
STR="Hello\nWorld"
echo -e $STR
#outputs
Hello
World
Если строка является результатом другой команды, я просто использую кавычки
indexes_diff=$(git diff index.yaml)
echo "$indexes_diff"
Проблема не в оболочке. Проблема на самом деле связана с командой echo
и отсутствием двойных кавычек вокруг интерполяции переменных. Вы можете попробовать использовать echo -e
, но это не поддерживается на всех платформах, и теперь одна из причин printf
теперь рекомендуется для переносимости.
Вы также можете попробовать и вставить новую строку непосредственно в свою оболочку скрипт (если скрипт - это то, что вы пишете), поэтому он выглядит как ...
#!/bin/sh
echo "Hello
World"
#EOF
или эквивалентно
#!/bin/sh
string="Hello
World"
echo "$string" # note double quotes!
$ STR='new
line'
$ printf '%s' "$STR"
new
line
Да, это означает запись Enter, где это необходимо в коде. 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
$ STR=$'new\nline'
$ echo '6e65770a6c696e650a' | xxd -p -r
new
line
Или $ echo "new line" | sed 's/ \+/\n/g'
new
line
То, что я сделал по другим ответам, было
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