Многострочная строка с дополнительными пробелами (сохраняем отступы)
Я хочу записать несколько предопределенных текстов в файл следующим образом:
text="this is line one\n
this is line two\n
this is line three"
echo -e $text > filename
Я ожидаю, что в файле получится что-то вроде этого:
this is line one
this is line two
this is line three
Но вместо этого я получаю следующий результат:
this is line one
this is line two
this is line three
Я уверен, что после каждого \n
нет пробелов, но откуда берется лишний пробел?
5 ответ(ов)
Heredoc действительно звучит более удобно для этой цели. Он используется для отправки нескольких команд в интерпретатор команд, такой как ex или cat.
Пример использования heredoc с командой cat
:
cat << EndOfMessage
Это строка 1.
Это строка 2.
Строка 3.
EndOfMessage
Строка после <<
указывает, где нужно остановиться.
Чтобы отправить эти строки в файл, вы можете использовать:
cat > $FILE <<- EOM
Строка 1.
Строка 2.
EOM
Также вы можете сохранить эти строки в переменной:
read -r -d '' VAR << EOM
Это строка 1.
Это строка 2.
Строка 3.
EOM
Это сохраняет строки в переменной с именем VAR
.
При выводе не забудьте использовать кавычки вокруг переменной, иначе вы не увидите символы новой строки:
echo "$VAR"
Еще лучше, вы можете использовать отступы, чтобы сделать код более читабельным. В этом случае просто добавьте -
после <<
, чтобы табуляция не отображалась.
read -r -d '' VAR <<- EOM
Это строка 1.
Это строка 2.
Строка 3.
EOM
Однако в этом случае вы должны использовать табуляции, а не пробелы, для отступов в вашем коде.
Если вы пытаетесь сохранить строку в переменной, есть простой способ сделать это следующим образом:
USAGE=$(cat <<-END
Это первая строка.
Это вторая строка.
Это третья строка.
END
)
Если вы используете табуляцию (т.е. \t
) для отступа текста, то отступ будет убран. Если вы используете пробелы, отступ останется.
ПРИМЕЧАНИЯ:
- Важно, чтобы закрывающая скобка находилась на другой строке. Текст
END
должен быть размещен на отдельной строке. - При использовании этой переменной, чтобы сохранить нечитаемые символы (
\t
,\n
), необходимо заключить её в кавычки. То есть, используйтеecho "$USAGE"
(не:echo $USAGE
).
Команда echo
добавляет пробелы между переданными ей аргументами. Переменная $text
подвергается расширению и разделению по словам, поэтому ваша команда echo
эквивалентна следующей:
echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n" ...
Как видно, пробел будет добавлен перед "this". Вы можете либо удалить символы новой строки и заключить $text
в кавычки, чтобы сохранить новые строки:
text="this is line one
this is line two
this is line three"
echo "$text" > filename
Либо вы можете использовать printf
, который более надежен и переносим, чем echo
:
printf "%s\n" "this is line one" "this is line two" "this is line three" > filename
В bash
, который поддерживает расширение фигурных скобок, вы даже можете сделать так:
printf "%s\n" "this is line "{one,two,three} > filename
В вашем Bash-скрипте вы можете использовать оба предложенных способа для записи текста с переводами строк в файл.
Первый метод использует экранирование (с помощью флага -e
для echo
), чтобы интерпретировать символы новой строки (\n
):
#!/bin/sh
text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename
Этот код создаст файл filename
, в котором будет текст с тремя строками, разделенными переводами строк.
Второй метод более простой и удобный – здесь вы просто записываете текст с переводами строк в переменную text
, заключив его в двойные кавычки:
text="this is line one
this is line two
this is line three"
echo "$text" > filename
Этот способ также даст тот же результат – файл filename
будет содержать текст с правильными переводами строк.
В результате, если вы выполните команду cat filename
, вы получите:
this is line one
this is line two
this is line three
Оба подхода корректны, но второй метод часто предпочтительнее за его простоту и читаемость.
Вот несколько решений, которые я нашел, если вы хотите, чтобы каждая строка была правильно отступлена:
Вы можете использовать
echo
:echo "это первая строка" \ "\n""это вторая строка" \ "\n""это третья строка" \ > имя_файла
Это не сработает, если вы поставите
"\n"
прямо перед\
в конце строки.В качестве альтернативы, вы можете использовать
printf
, что обеспечит лучшую переносимость (у меня было много проблем сecho
):printf '%s\n' \ "это первая строка" \ "это вторая строка" \ "это третья строка" \ > имя_файла
Еще одно решение может выглядеть так:
text='' text="${text}это первая строка\n" text="${text}это вторая строка\n" text="${text}это третья строка\n" printf "%b" "$text" > имя_файла
или
text='' text+="это первая строка\n" text+="это вторая строка\n" text+="это третья строка\n" printf "%b" "$text" > имя_файла
Еще одно решение можно получить, комбинируя
printf
иsed
:if что-то then printf '%s' ' это первая строка это вторая строка это третья строка ' | sed '1d;$d;s/^ //g' fi
Сложно рефакторить код, отформатированный таким образом, так как вы жестко зашиваете уровень отступа в код.
Также возможно использовать вспомогательную функцию и некоторые приемы подстановки переменных:
unset text _() { text="${text}${text+ }${*}"; } # Это пустая строка, которая демонстрирует логику использования # "+" вместо ":+" в подстановке переменных выше. _ "" _ "это первая строка" _ "это вторая строка" _ "это третья строка" unset -f _ printf '%s' "$text"
Выберите один из этих способов в зависимости от ваших потребностей и предпочтений.
Как проверить, содержит ли строка подстроку в Bash
Извлечение подстроки в Bash
Как изменить цвет вывода echo в Linux
Как выводить команды оболочки по мере их выполнения
Назначение значений по умолчанию для переменных оболочки одной командой в bash