Jak określić wielowierszową zmienną powłoki?

122

Napisałem zapytanie:

function print_ui_hosts
{
local sql = "select ........."
print_sql "$ sql"
}

local sql - bardzo długi ciąg. Zapytanie nie jest sformatowane. Jak mogę podzielić ciąg na wiele linii?

user2219963
źródło
4
Co shelltu dobrze gadasz? Powinien batchbyć, bashczy naprawdę jesteś z ciemnej strony?
Chris Seymour
1
jeśli jest to powłoka / bash, nie należy otaczać =spacjami.
Nik O'Lai

Odpowiedzi:

138

Użyj readz heredocem, jak pokazano poniżej:

read -d '' sql << EOF
select c1, c2 from foo
where c1='something'
EOF

echo "$sql"
dogbane
źródło
52
Zauważ, że readw tej sytuacji będzie miał kod zakończenia 1; jeśli to ma znaczenie (na przykład biegasz z set -e), będziesz chciał dodać || truena końcu pierwszej linii.
chepner
4
set -ezamyka powłokę, jeśli polecenie ma „nieoczekiwany” niezerowy kod zakończenia. Przez „nieprzewidziane” rozumiem, że działa w kontekście, w którym nie patrzysz konkretnie na status wyjścia. falsena przykład samo z siebie opuściłoby powłokę. false || truenie, ponieważ oczekujesz niezerowego kodu wyjścia, określając inną komendę do uruchomienia, jeśli pierwsza zakończy się niepowodzeniem.
chepner
1
Problem z zestawem -e i odczytem (patrz ostatnie ćwiczenie) jest szczegółowo opisany tutaj: mywiki.wooledge.org/BashFAQ/105
Niklas Peter
5
co -d ' 'tu robi?
hg_git
3
@hg_git Mówi, readaby nie przerywać czytania w przypadku napotkania nowej linii.
Cyker,
171

po prostu wstaw nową linię w razie potrzeby

sql="
SELECT c1, c2
from Table1, Table2
where ...
"

powłoka będzie szukać zamykającego cudzysłowu

Nik O'Lai
źródło
7
niezbyt dobre rozwiązanie, jeśli zapytanie sql zawiera cudzysłowy. Będziesz musiał przed nimi uciec i zrobi się bałagan.
zgubienie psów
13
Podwójne cudzysłowy @dogbane pojawiają się rzadko w większości dialektów SQL, więc w praktyce jest to czyste.
Iain Samuel McLean Elder
4
Następnie zawiń ciąg w pojedyncze cudzysłowy.
tripleee
Nie jestem pewien, dlaczego chcesz lub potrzebujesz przełamania linii wiodącej. W mojej aplikacji nie zrobiłem, więc właśnie zacząłemsql="SELECT c2, c2
bhfailor
1
Zabawne, że wydaje się to zbyt łatwe, aby mogło być prawdziwe. FYI, aby dodać DQ, po prostu utwórz zmienną DQ = '\ "', a następnie odwołaj się do niej w instrukcji za pomocą $ {DQ}.
Timothy C. Quinn
69

Chciałbym udzielić jednej dodatkowej odpowiedzi, podczas gdy inne w większości przypadków wystarczą.

Chciałem napisać ciąg w wielu wierszach, ale jego zawartość musiała być jednowierszowa.

sql="                       \
SELECT c1, c2               \
from Table1, ${TABLE2}      \
where ...                   \
"

Przepraszam, jeśli to trochę nie na temat (nie potrzebowałem tego do SQL). Jednak ten post pojawia się jako jeden z pierwszych wyników wyszukiwania wielowierszowych zmiennych powłoki, a dodatkowa odpowiedź wydawała się odpowiednia.

islijepcevic
źródło
1
Nawet bez tego moja treść wychodzi w jednej linii.
papiro
12
@papiro, spróbuj echo "$sql"zamiast echo $sql.
Michael Mol
@MichaelMol - Około dwie dekady po mojej pierwszej instalacji Linuksa i wciąż uczę się czegoś nowego. Dzięki za tę "sztuczkę".
Seth
6

Dzięki odpowiedzi dimo414 na podobne pytanie , pokazuje to, jak działa jego świetne rozwiązanie, i pokazuje, że możesz łatwo mieć cudzysłowy i zmienne w tekście:

przykładowe dane wyjściowe

$ ./test.sh

The text from the example function is:
  Welcome dev: Would you "like" to know how many 'files' there are in /tmp?

  There are "      38" files in /tmp, according to the "wc" command

test.sh

#!/bin/bash

function text1()
{
  COUNT=$(\ls /tmp | wc -l)
cat <<EOF

  $1 Would you "like" to know how many 'files' there are in /tmp?

  There are "$COUNT" files in /tmp, according to the "wc" command

EOF
}

function main()
{
  OUT=$(text1 "Welcome dev:")
  echo "The text from the example function is: $OUT"
}

main
Brad Parks
źródło
5

readnie eksportuje zmiennej (co jest dobre przez większość czasu). Oto alternatywa, którą można wyeksportować za pomocą jednego polecenia, która może zachować lub odrzucić wysunięcia wiersza i umożliwia mieszanie stylów cytowania według potrzeb. Działa dla bash i zsh.

oneLine=$(printf %s \
    a   \
    " b "   \
    $'\tc\t'    \
    'd '    \
)
multiLine=$(printf '%s\n' \
    a   \
    " b "   \
    $'\tc\t'    \
    'd '    \
)

Przyznaję, że potrzeba cytowania sprawia, że ​​jest to brzydkie dla SQL, ale odpowiada (bardziej ogólnie) na pytanie w tytule.

Używam tego w ten sposób

export LS_COLORS=$(printf %s    \
    ':*rc=36:*.ini=36:*.inf=36:*.cfg=36:*~=33:*.bak=33:*$=33'   \
    ...
    ':bd=40;33;1:cd=40;33;1:or=1;31:mi=31:ex=00')

w pliku pochodzącym zarówno z my, jak .bashrci .zshrc.

EndlosSchleife
źródło