Jak działa "cat

Musiałem napisać skrypt, aby wprowadzić wejście Wielowierszowe do programu (psql).

Po odrobinie googlowania znalazłem następującą składnię:

cat << EOF | psql ---params
BEGIN;

`pg_dump ----something`

update table .... statement ...;

END;
EOF

To poprawnie konstruuje ciąg wielowierszowy (od BEGIN; do END;, włącznie) i przekazuje go jako wejście do psql.

Ale nie mam pojęcia jak/dlaczego to działa, czy ktoś może wyjaśnić?

Mam na myśli głównie cat << EOF, wiem > wyjścia do pliku, >> dołącza do pliku, < odczytuje wejście z plik.

Co dokładnie robi <<?

I czy jest do tego jakaś strona podręcznika?

Author: Benjamin W., 2010-03-23

7 answers

To się nazywa heredoc format zapewniający ciąg znaków na stdin. Zobacz https://en.wikipedia.org/wiki/Here_document#Unix_shells Po Więcej Szczegółów.


From man bash:

Tutaj Dokumenty

Ten typ przekierowania nakazuje powłoce odczytywanie danych wejściowych z źródło prądu aż do linii zawierające tylko słowo (bez końców blanki) jest widoczne.

Wszystkie linie odczytane do tego punktu są następnie używane jako na standardowe wejście dla polecenia.

Format Dokumentów tutaj jest:

          <<[-]word
                  here-document
          delimiter

Brak rozszerzania parametrów, zastępowania poleceń, rozszerzania arytmetycznego lub rozszerzenie pathname jest wykonywane na słowo . Jeśli dowolne znaki w słowie są quoted, the ogranicznik jest wynikiem usuwania cudzysłowu na wyrazie , A linie w tutaj-dokument nie są rozszerzane. Jeśli słowo nie jest cytowane, wszystkie linie tutaj-dokument są poddawane rozbudowie parametrów, polecenie podstawienie i arytmetyka ekspansja. W tym ostatnim przypadku sekwencja znaków \<newline> jest ignorowane i \ muszą być użyte do cytowania znaków \, $, i `.

Jeśli operatorem przekierowania jest <<-, to wszystkie znaki tabulacji są usuwane z linii wejściowych i linia zawierająca ogranicznik . To pozwala tutaj-dokumenty wewnątrz skryptów powłoki być wcięte w naturalna Moda.

 376
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-26 04:53:16

Składnia cat <<EOF jest bardzo przydatna podczas pracy z tekstem wielowierszowym w Bash, np. podczas przypisywania wielowierszowego łańcucha do zmiennej powłoki, pliku lub potoku.

Przykłady użycia składni cat <<EOF w Bash:

1. Przypisanie wielowierszowego łańcucha do zmiennej powłoki

$ sql=$(cat <<EOF
SELECT foo, bar FROM db
WHERE foo='baz'
EOF
)

zmienna $sql zawiera teraz również znaki nowej linii. Możesz sprawdzić za pomocą echo -e "$sql".

2. Przekazywanie ciągów wielowierszowych do pliku w Bash

$ cat <<EOF > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
EOF

print.sh plik teraz zawiera:

#!/bin/bash
echo $PWD
echo /home/user

3. Przekazuj ciąg wielowierszowy do rury w Bash

$ cat <<EOF | grep 'b' | tee b.txt
foo
bar
baz
EOF

plik b.txt zawiera linie bar i baz. To samo wyjście jest drukowane do stdout.

 343
Author: Vojtech Vitek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-14 22:01:53

W Twoim przypadku, " EOF "jest znany jako "tutaj Tag". Zasadniczo <<Here mówi powłoce, że zamierzasz wprowadzić ciąg wielowierszowy aż do "znacznika" Here. Możesz nazwać ten tag jak chcesz, często jest to EOF lub STOP.

Niektóre zasady dotyczące tagów tutaj:

  1. znacznik może być dowolnym ciągiem znaków, wielkimi lub małymi literami, chociaż większość ludzi używa wielkich liter zgodnie z konwencją.
  2. znacznik nie będzie uważany za znacznik Here, jeśli w tej linii znajdują się inne słowa. W takim przypadku będzie / align = "left" / Znacznik powinien znajdować się sam w osobnej linii, aby można go było uznać za znacznik.
  3. znacznik nie powinien mieć spacji wiodącej ani końcowej w tej linii, aby można go było uznać za znacznik. W przeciwnym razie będzie on uważany za część ciągu znaków.

Przykład:

$ cat >> test <<HERE
> Hello world HERE <-- Not by itself on a separate line -> not considered end of string
> This is a test
>  HERE <-- Leading space, so not considered end of string
> and a new line
> HERE <-- Now we have the end of the string
 157
Author: edelans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-02 09:31:14

POSIX 7

Kennytm cytuje man bash, ale większość z nich to również POSIX 7: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04 :

Operatory przekierowujące "

Tutaj-dokument jest traktowany jako pojedyncze słowo, które zaczyna się po następnym i trwa aż do linia zawierająca tylko ogranicznik i a, bez znaków pomiędzy nimi. Następnie rozpoczyna się następny dokument tutaj, jeśli taki istnieje. Format jest następujący:

[n]<<word
    here-document
delimiter

Gdzie opcjonalne n reprezentuje numer deskryptora pliku. Jeśli liczba jest pominięta, dokument here odnosi się do standardowego wejścia (deskryptor pliku 0).

Jeśli jakikolwiek znak w programie word jest cytowany, ogranicznik tworzy się poprzez usunięcie cudzysłowu w programie word, a linie here-document nie być rozszerzony. W przeciwnym razie ogranicznikiem jest samo słowo.

Jeśli żadne znaki w programie word nie są cytowane, wszystkie linie dokumentu here powinny zostać rozszerzone w celu rozszerzenia parametrów, zastąpienia poleceń i rozszerzenia arytmetycznego. W tym przypadku wejście zachowuje się jak wewnętrzne podwójne cudzysłowy (zobacz podwójne cudzysłowy). Jednak znak podwójnego cytowania ( "" ) nie jest traktowany specjalnie w dokumencie here, z wyjątkiem sytuacji, gdy podwójny cytat pojawia się w dokumencie here "$()", "`", lub "${}".

Jeśli symbolem przekierowania jest"<tab> są usuwane z linii wejściowych i linii zawierającej ogranicznik końcowy. Jeżeli w wierszu podano więcej niż jeden operator "

Gdy dokument here jest odczytywany z urządzenia końcowego i powłoka jest interaktywna, zapisuje zawartość zmiennej PS2, przetworzonej w sposób opisany w zmiennych powłoki, do standardowego błędu przed odczytaniem każdej linii wejścia, aż do rozpoznania ogranicznika.

Przykłady

Niektóre przykłady jeszcze nie podane.

Cudzysłowy zapobiegają rozszerzaniu parametrów

Bez cudzysłowów:

a=0
cat <<EOF
$a
EOF

Wyjście:

0

Z cytatami:

a=0
cat <<'EOF'
$a
EOF

Lub (brzydki, ale ważny):

a=0
cat <<E"O"F
$a
EOF

Wyjścia:

$a

Myślnik usuwa początek tabs

Bez myślnika:

cat <<EOF
<tab>a
EOF

Gdzie <tab> jest literalną tabulatorem i można ją wstawić za pomocą Ctrl + V <tab>

Wyjście:

<tab>a

Z myślnikiem:

cat <<-EOF
<tab>a
<tab>EOF

Wyjście:

a

Istnieje to oczywiście po to, abyś mógł wciąć swój cat jak otaczający kod, który jest łatwiejszy do odczytania i utrzymania. Np.:

if true; then
    cat <<-EOF
    a
    EOF
fi

Niestety, nie działa to dla znaków spacji: POSIX faworyzował tab wcięcia tutaj. Kurczę.

 47
Author: Ciro Santilli 新疆改造中心 六四事件 法轮功,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-25 14:51:36

Używanie tee zamiast cat

Nie do końca jako odpowiedź na pierwotne pytanie, ale i tak chciałem się tym podzielić: miałem potrzebę utworzenia pliku konfiguracyjnego w katalogu, który wymagał praw roota.

W tym przypadku nie działa:

$ sudo cat <<EOF >/etc/somedir/foo.conf
# my config file
foo=bar
EOF

Ponieważ przekierowanie jest obsługiwane poza kontekstem sudo.

Zamiast tego użyłem tego:

$ sudo tee <<EOF /etc/somedir/foo.conf >/dev/null
# my config file
foo=bar
EOF
 16
Author: Andreas Maier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-13 12:14:06

Niekoniecznie jest to odpowiedź na pierwotne pytanie, ale dzielenie się wynikami z moich własnych testów. To:

<<test > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
test

Wytworzy ten sam plik co:

cat <<test > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
test
Nie widzę sensu używania komendy cat.
 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-06 00:15:40

Warto zauważyć, że tutaj dokumenty działają również w pętlach bash. Ten przykład pokazuje, jak uzyskać listę kolumn tabeli:

export postgres_db_name='my_db'
export table_name='my_table_name'

# start copy 
while read -r c; do test -z "$c" || echo $table_name.$c , ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
SELECT column_name
FROM information_schema.columns
WHERE 1=1
AND table_schema = 'public'
AND table_name   =:'table_name'  ;
EOF
)
# stop copy , now paste straight into the bash shell ...

output: 
my_table_name.guid ,
my_table_name.id ,
my_table_name.level ,
my_table_name.seq ,

Lub nawet bez nowej linii

while read -r c; do test -z "$c" || echo $table_name.$c , | perl -ne 
's/\n//gm;print' ; done < <(cat << EOF | psql -t -q -d $postgres_db_name -v table_name="${table_name:-}"
 SELECT column_name
 FROM information_schema.columns
 WHERE 1=1
 AND table_schema = 'public'
 AND table_name   =:'table_name'  ;
 EOF
 )

 # output: daily_issues.guid ,daily_issues.id ,daily_issues.level ,daily_issues.seq ,daily_issues.prio ,daily_issues.weight ,daily_issues.status ,daily_issues.category ,daily_issues.name ,daily_issues.description ,daily_issues.type ,daily_issues.owner
 0
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-14 15:18:35