Bash продолжения
Как вы используете строки продолжения bash?
Я понимаю, что вы можете это сделать:
echo "continuation \
lines"
>continuation lines
Однако, если у вас есть отложенный код, он не работает так хорошо:
echo "continuation \
lines"
>continuation lines
Ответы
Ответ 1
Это то, что вы можете пожелать
$ echo "continuation"\
> "lines"
continuation lines
Если это создает два аргумента для эха, и вы их только хотите, тогда давайте посмотрим на конкатенацию строк. В bash, помещая две строки рядом друг с другом, конкатенатете:
$ echo "continuation""lines"
continuationlines
Таким образом, строка продолжения без отступа является одним из способов разбить строку:
$ echo "continuation"\
> "lines"
continuationlines
Но когда используется отступ:
$ echo "continuation"\
> "lines"
continuation lines
Вы получаете два аргумента, потому что это уже не конкатенация.
Если вы хотите, чтобы одна строка пересекала строки, в то время как отступы, но не получая все эти пробелы, можно использовать один подход, чтобы вырезать линию продолжения и использовать переменные:
$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines
Это позволит вам иметь чистый код с отступом за счет дополнительных переменных. Если вы сделаете переменные локальными, это не должно быть слишком плохо.
Ответ 2
Здесь документы с терминатором <<-HERE
хорошо работают для многострочных текстовых строк с отступом. Это удалит все ведущие вкладки из документа здесь. (Ограничители строки все равно останутся.)
cat <<-____HERE
continuation
lines
____HERE
Смотри также http://ss64.com/bash/syntax-here.html
Если вам нужно сохранить некоторые, но не все ведущие пробелы, вы можете использовать что-то вроде
sed 's/^ //' <<____HERE
This has four leading spaces.
Two of them will be removed by sed.
____HERE
или, возможно, используйте tr
, чтобы избавиться от новых строк:
tr -d '\012' <<-____
continuation
lines
____
(Во второй строке есть вкладка и пробел впереди; вкладка будет удалена оператором тире перед терминатором heredoc, тогда как пробел будет сохранен.)
Для наложения длинных сложных строк на несколько строк мне нравится printf
:
printf '%s' \
"This will all be printed on a " \
"single line (because the format string " \
"does not specify any newline)"
Это также хорошо работает в тех случаях, когда вы хотите встроить нетривиальные фрагменты сценария оболочки в другой язык, где синтаксис основного языка не позволяет использовать документ здесь, например, в Makefile
или Dockerfile
.
printf '%s\n' >./myscript \
'#!/bin/sh' \
"echo \"G'day, World\"" \
'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript
Ответ 3
Вы можете использовать массивы bash
$ str_array=("continuation"
"lines")
затем
$ echo "${str_array[*]}"
continuation lines
есть дополнительный пробел, потому что (после руководства bash):
Если слово в двойных кавычках, ${name[*]}
расширяется до одного слова с значение каждого члена массива, разделенного первым символом Переменная IFS
Поэтому установите IFS=''
, чтобы избавиться от лишнего пространства
$ IFS=''
$ echo "${str_array[*]}"
continuationlines
Ответ 4
Я столкнулся с ситуацией, когда мне пришлось отправить длинное сообщение как часть аргумента команды и пришлось придерживаться ограничения длины строки. Команды выглядят примерно так:
somecommand --message="I am a long message" args
То, как я решил это, - это переместить сообщение как документ здесь (например, предложенный вариант @tripleee). Но здесь документ становится stdin, поэтому его нужно прочитать снова, я пошел с подходом ниже:
message=$(
tr "\n" " " <<- END
This is a
long message
END
)
somecommand --message="$message" args
Это имеет то преимущество, что $message
можно использовать точно как строковая константа без лишних пробелов или разрывов строк.
Обратите внимание, что фактические строки сообщений, приведенные выше, имеют префикс с символом tab
, который разделяется самим документом (из-за использования <<-
). В конце есть разрывы строк, которые затем заменяются на dd
пробелами.
Обратите внимание также, что если вы не удаляете новые строки, они будут отображаться как есть, когда "$message"
будет расширен. В некоторых случаях вы можете обходным путем, удалив двойные кавычки вокруг $message
, но сообщение больше не будет единственным аргументом.
Ответ 5
Вы можете просто отделить его с помощью новых строк (без использования обратной косой черты), как это требуется внутри отступа, как показано ниже, и просто удалить новые строки.
Пример:
echo "continuation
of
lines" | tr '\n' ' '
Или, если это определение переменной, новые строки автоматически преобразуются в пробелы. Таким образом, лишние пробелы, только если применимо.
x="continuation
of multiple
lines"
y="red|blue|
green|yellow"
echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case
Ответ 6
Это не совсем то, о чем просил пользователь, но еще один способ создать длинную строку, которая занимает несколько строк, - это постепенно наращивать ее, например, так:
$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World
Очевидно, что в этом случае было бы проще создать его за один раз, но этот стиль может быть очень легким и понятным при работе с более длинными строками.
Ответ 7
Однако, если у вас есть отложенный код, он не работает так хорошо:
echo "continuation \
lines"
>continuation lines
Попробуйте использовать одинарные кавычки и конкатенировать строки:
echo 'continuation' \
'lines'
>continuation lines
Примечание. Конкатенация включает пробел.
Ответ 8
В зависимости от того, какие риски вы принимаете и насколько хорошо вы знаете и доверяете данным, вы можете использовать упрощенную интерполяцию переменных.
$: x="
this
is
variably indented
stuff
"
$: echo "$x" # preserves the newlines and spacing
this
is
variably indented
stuff
$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff
Ответ 9
В некоторых сценариях может быть целесообразно использовать возможность конкатенации Bash.
Пример:
temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines
Из раздела ПАРАМЕТРЫ страницы Bash Man:
name=[value]...
... В контексте, где оператор присваивания присваивает значение переменной оболочки или индексу массива, оператор + = может использоваться для добавления или добавления к предыдущему значению переменной. Когда + = применяется к переменной, для которой был задан целочисленный атрибут, значение оценивается как арифметическое выражение и добавляется к текущему значению переменной, которое также оценивается. Когда + = применяется к переменной массива с использованием составного присваивания (см. массивы ниже), значение переменной не сбрасывается (как при использовании =), и новые значения добавляются в массив, начиная с единицы, большей индекса максимума массива (для индексированных массивов) или добавляются как дополнительные пары ключ-значение в ассоциативном массиве. При применении к строковой переменной значение раскрывается и добавляется к значению переменной.
Ответ 10
Это, вероятно, не отвечает на ваш вопрос, но в любом случае вы можете найти его полезным.
Первая команда создает script, который отображается второй командой.
Третья команда делает этот script исполняемый файл.
Четвертая команда предоставляет пример использования.
[email protected]:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n """Dedent all but the first line in the passed `text`."""\n try:\n first, rest = text.split("\\n", 1)\n return "\\n".join([first, textwrap.dedent(rest)])\n except ValueError:\n return text # single-line string\n\nprint bash_dedent(sys.argv[1])' > bash_dedent
[email protected]:~/tmp/so$ cat bash_dedent
#!/usr/bin/env python
import textwrap, sys
def bash_dedent(text):
"""Dedent all but the first line in the passed `text`."""
try:
first, rest = text.split("\n", 1)
return "\n".join([first, textwrap.dedent(rest)])
except ValueError:
return text # single-line string
print bash_dedent(sys.argv[1])
[email protected]:~/tmp/so$ chmod a+x bash_dedent
[email protected]:~/tmp/so$ echo "$(./bash_dedent "first line
> second line
> third line")"
first line
second line
third line
Обратите внимание, что если вы действительно хотите использовать этот script, имеет смысл перемещать исполняемый файл script в ~/bin
, чтобы он был на вашем пути.
Проверьте ссылку на python, чтобы узнать, как работает textwrap.dedent
.
Если использование $'...'
или "$(...)"
запутывает вас, задайте другой вопрос (по одному для каждой конструкции), если его еще нет. Возможно, было бы неплохо предоставить ссылку на вопрос, который вы найдете/попросите, чтобы у других людей была ссылка.