Як вивести багаторядковий рядок у Bash?


250

Як я можу вивести багаторядковий рядок у Bash, не використовуючи кілька ехо-дзвінків, як-от так:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

Я шукаю портативний спосіб зробити це, використовуючи лише вбудовані Bash.


4
Якщо ви виводите повідомлення про використання у відповідь на неправильне виклик, зазвичай це повідомлення буде надіслано стандартною помилкою замість стандартного виводу,echo >&2 ...
Марк Рід

2
@MarkReed Повідомлення про використання виводиться введенням --help(який повинен перейти в стандартний режим).
helpermethod

Для інших, хто приходить разом, можна отримати більше інформації про "тут документи": tldp.org/LDP/abs/html/here-docs.html
Джеффрі Мартінес

Перевірте printfрішення на основі Gordon Davidson. Незважаючи на те, що перебуває в тіні echoабо catна основі підходів, це здається набагато меншою мірою. Напевно, синтаксис `printf 'являє собою трохи кривої навчання, але я хотів би дізнатись про інші недоліки (? Сумісність, продуктивність? ...)
mvv

Відповіді:


296

Тут часто використовуються документи для цієї мети.

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

Вони підтримуються у всіх оболонках, отриманих від Bourne, включаючи всі версії Bash.


4
Так - але catце не вбудований.
Марк Рід

8
@MarkReed: Це правда, але вона завжди доступна (за винятком можливо, за незвичних обставин).
Призупинено до подальшого повідомлення.

6
+1 Thx. Я закінчив використовувати read -d '' help <<- EOF ...для читання багаторядкової рядок у змінну, а потім повторив результат.
helpermethod

3
чи можу я зберегти HEREDOC до змінної?
chovy

177

або ви можете це зробити:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "

1
@OliverWeiler: Він буде працювати навіть у снарядах Борна, таких як Даш та Ранкова оболонка Борна .
Призупинено до подальшого повідомлення.

6
Не чудово, якщо вам це потрібно в функції, тому що вам або потрібно буде 1) викреслити рядок до кінця ліворуч від вашого файлу, або 2) тримати його з відступом, щоб узгоджуватися з рештою коду, але потім він друкує з відступи також
серп

43

Надихнувшись проникливими відповідями на цій сторінці, я створив змішаний підхід, який вважаю найпростішим та гнучкішим. Що ти думаєш?

По-перше, я визначаю використання в змінній, що дозволяє мені повторно використовувати його в різних контекстах. Формат дуже простий, майже WYSIWYG, без необхідності додавати будь-які контрольні символи. Це здається мені досить портативним (я запускав його на MacOS і Ubuntu)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

Тоді я можу просто використовувати його як

echo "$__usage"

а ще краще, коли ми аналізуємо параметри, я можу просто повторити його там, в одному вкладиші:

levelN=${2:?"--level: n is required!""${__usage}"}

4
це працювало для мене в сценарії, де вищевказана відповідь не (без змін).
Девід Уелч

3
Це набагато чіткіше, ніж залучати купу символів, таких як \ t і \ n, яких важко знайти в тексті та розгорнути, щоб зробити висновок набагато іншим, ніж рядок у сценарії
sg

1
Чомусь він друкує все на тій же лінії для мене: /
Ніколя де Фонтеней

2
@Nicolas: Використання подвійних лапок в echo "$__usage"мені було необхідним. echo $__usageне працює.
Маріо

24

Використовуйте -eопцію, тоді ви можете надрукувати новий рядок із символом \nу рядку.

Зразок (але не впевнений, хороший він чи ні)

Найцікавіше, що цей -eваріант не зафіксований на головній сторінці MacOS, поки він є корисним. Це задокументовано на довідковій сторінці Linux .


6
Ці підручні сторінки призначені для системної echoкоманди /bin/echo, яка в Mac OS не має -eможливості. коли ви використовуєте bash для цих систем, його вбудована echoкоманда бере на себе. Це можна побачити, чітко ввівши /bin/echo whateverта спостерігаючи за різницею в поведінці. Щоб переглянути документацію на вбудований, введіть help echo.
Марк Рід

1
/bin/echoчасто відрізняється від однієї ОС до іншої та відрізняється від вбудованої Bash echo.
Призупинено до подальшого повідомлення.

@MarkReed: Я спробую пізніше, але дякую за інформацію. +1. Я просто залишу свою відповідь тут, оскільки триває досить багато хороших дискусій.
nhahtdh

7
echo -eне є портативним - наприклад, деякі реалізації echo надрукують "-e" як частину виводу. Якщо ви хочете портативність, використовуйте замість printf. Наприклад, / bin / echo в OS X 10.7.4 робить це. IIRC bash вбудований ехо також був дивним під 10.5.0, але я більше не пам'ятаю деталей.
Гордон Девіссон

2
echo -eпокусав мене раніше ... Однозначно використовуйте printfабо catз гередоком. <<-Варіант тут документи особливо приємно , тому що ви можете роздягнутися провідними відступи на виході, але відступи для зручності читання в сценарії
zbeekman

22

Оскільки я рекомендував printfу коментарі, я, мабуть, маю навести кілька прикладів його використання (хоча для друку повідомлення про використання я скоріше використовую відповіді Денніса чи Кріса). printfє трохи складнішим у використанні, ніж echo. Перший її аргумент - це рядковий формат, в якому витлумачення (як \n) завжди інтерпретуються; він також може містити директиви щодо формату, починаючи з того %, які контролюють, де і як додаткові аргументи включаються до нього. Ось два різні підходи до його використання для повідомлення про використання:

По-перше, ви можете включити все повідомлення в рядок формату:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

Зауважте, що на відміну від цього echo, ви повинні чітко включити фінальний новий рядок. Крім того, якщо повідомлення містить будь-які %символи, вони повинні бути записані як %%. Якщо ви хочете включити адреси bugreport та домашньої сторінки, їх можна додати цілком природно:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

По-друге, ви можете просто використовувати рядок формату, щоб змусити його друкувати кожен додатковий аргумент в окремому рядку:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

За допомогою цієї опції додавання адрес бугрепорту та домашньої сторінки є досить очевидним:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"

9

Також з відступним вихідним кодом ви можете використовувати <<-(з кінцевим тире), щоб ігнорувати ведучі вкладки (але не провідні пробіли). Наприклад це:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

Виводить текст з відступом без провідного пробілу:

line1
line2

Це для мене не вийшло. Яку оболонку ви використовуєте?
чотири43

Не працював у bash 4.4.19 в Ubuntu. Він не
прибрав

1
@ four43, Ви мали рацію. Не працює для видалення провідних пробілів. Однак видаляє провідні вкладки. Тому я виправив свою відповідь з вкладок і пробілів, до вкладок, а не пробілів. Вибачте за помилку. Я перевірив посібник, і він чітко говорить, що вкладки видалені. Дякую за те, що ви звернули на це увагу.
Еліптичний вигляд

0

Якщо ви використовуєте рішення від @jorge і виявите, що все знаходиться в одному рядку, переконайтеся, що ви додаєте змінну до лапок:

echo $__usage

буде надрукувати все в одному рядку, тоді як

echo "$__usage"

збереже нові рядки.


Це насправді єдине рішення, яке працювало на мене. Printf робить багато речей, і з моїм багаторядковим xml, ймовірно, потрібно багато втечі, оскільки він повністю керує вмістом. Я призначаю foo = cat <<EOF .... EOF&& echo "$ foo"
Джиллес ван Гурп
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.