Как "кошка

мне нужно написать скрипт для ввода многострочного ввода в программу (psql).

после немного гуглить, я нашел следующие синтаксические работы:

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

`pg_dump ----something`

update table .... statement ...;

END;
EOF

это правильно создает многострочную строку (от BEGIN; to END; включительно) и трубы его в качестве вклада в psql.

но я понятия не имею, как/почему это работает, Может кто-нибудь объяснить?

я имею в виду в основном cat << EOF Я знаю > вывод в файл, >> дописывает в файл < считывает входные данные из файла.

что значит << точно?

и есть ли для этого страница?

7 ответов


это называется помощи heredoc формат для предоставления строки в stdin. Вижу https://en.wikipedia.org/wiki/Here_document#Unix_shells для более подробной информации.


С man bash:

Здесь Документы

этот тип перенаправления инструктирует оболочку считывать входные данные из источник тока до строки содержит только слово (без трейлинга холостые) видно.

все строки, прочитанные до этой точки, затем используются в качестве стандартный ввод для команды.

формат здесь-документы:

          <<[-]word
                  here-document
          delimiter

отсутствие расширения параметра, замены команды, арифметического расширения, или расширение пути выполняется на слово. Если какие-либо символы слово несколько цитирую: разделитель является результатом удаления цитаты на слово, а линии в здесь-документ не расширены. Если слово без кавычек, все строки здесь-документ подвергаются к расширению параметра, команде замена и арифметика расширение. В последнем случае последовательность символов \<newline> is игнорируется, и \ необходимо цитата символы \, $ и `.

если оператор перенаправления <<-, то все ведущие символы табуляции удаляются из входных строк и строка, содержащая разделитель. Этот позволяет здесь-документы в сценариях оболочки должны быть отступами естественным образом.


на cat <<EOF синтаксис очень полезен при работе с многострочным текстом в Bash, например. при назначении многострочной строки переменной оболочки, файлу или каналу.

примеры cat <<EOF использование синтаксиса в Bash:

1. Назначьте многострочную строку переменной оболочки

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

на $sql переменная теперь содержит символы новой строки. Вы можете проверить с помощью echo -e "$sql".

2. Передать многострочную строку в файл в Баш

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

на содержит:

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

3. Передайте многострочную строку трубе в Bash

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

на содержит bar и baz строки. Тот же вывод печатается в stdout.


в вашем случае "EOF "известен как"здесь тег". В основном <<Here сообщает оболочке, что вы собираетесь ввести многострочную строку, пока "тег"Here. Вы можете назвать этот тег, как вы хотите, это часто EOF или STOP.

некоторые правила о тегах здесь:

  1. тегом может быть любая строка, верхний или нижний регистр, хотя большинство людей используют верхний регистр по соглашению.
  2. тег не будет рассматриваться как тег здесь, Если есть другие слова в эта линия. В этом случае он будет просто считаться частью строки. Тег должен быть сам по себе на отдельной строке, чтобы считаться тегом.
  3. в теге не должно быть ведущих или конечных пробелов в этой строке, чтобы считаться тегом. В противном случае он будет рассматриваться как часть строки.

пример:

$ 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

POSIX 7

kennytm цитирует man bash, но большая часть этого также POSIX 7: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_04:

операторы перенаправления "

здесь-документ должен рассматриваться как одно слово, которое начинается после следующего и продолжается до тех пор , пока не появится строка, содержащая только разделитель и a, без символов между ними. Затем начинается следующий здесь-документ, если он есть. Формат выглядит следующим образом:

[n]<<word
    here-document
delimiter

где необязательный n представляет номер дескриптора файла. Если номер опущен, то здесь-документ ссылается на стандартный ввод (файловый дескриптор 0).

если какой-либо символ в слове цитируется, разделитель должен быть сформирован путем выполнения цитаты удаление по word, а строки здесь-документа не должны расширяться. В противном случае разделителем будет само слово.

если в word нет кавычек, все строки документа здесь должны быть расширены для расширения параметров, замены команд и арифметического расширения. В этом случае in input ведет себя как внутренние двойные кавычки (см. двойные кавычки). Однако символ двойной кавычки ( '"' ) не должен рассматриваться специально в рамках настоящего документа, за исключением когда двойная кавычка появляется внутри "$()", "`", или" ${}".

если символ перенаправления "<tab> символы должны быть удалены из входных строк и строки, содержащей конечный разделитель. Если в строке указано более одного оператора "

когда здесь-документ считывается из терминальное устройство и оболочка интерактивны, он должен записать содержимое переменной PS2, обработанной, как описано в переменных оболочки, к стандартной ошибке перед чтением каждой строки ввода, пока разделитель не будет распознан.

примеры

некоторые примеры еще не приведены.

кавычки предотвращают расширение параметра

без кавычек:

a=0
cat <<EOF
$a
EOF

выход:

0

С цитаты:

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

или (некрасиво, но действует):

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

выходы:

$a

дефис удаляет ведущие вкладки

без дефиса:

cat <<EOF
<tab>a
EOF

здесь <tab> вкладка буквальном, и может быть вставлен с Ctrl + V <tab>

выход:

<tab>a

с дефисом:

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

выход:

a

это существует конечно, так что вы можете в начале cat как окружающие код, который легче читать и поддерживать. Е. Г.:

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

к сожалению, это не работает для пробелов: POSIX favored tab вдавливания здесь. Хлоп.


использование tee вместо cat

не совсем как ответ на исходный вопрос, но я все равно хотел поделиться этим: мне нужно было создать файл конфигурации в каталоге, который требует прав root.

в этом случае не работает следующее:

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

потому что перенаправление обрабатывается вне контекста sudo.

вместо этого я использовал это:

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

это не ответ на исходный вопрос, но некоторые результаты моих собственных тестов. Это:

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

создаст тот же файл, что и:

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

Итак, я не вижу смысла использовать команду cat.


стоит отметить,что здесь Документы работают и в циклах bash. В этом примере показано, как получить список столбцов таблицы:

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 ,

или даже без новой строки

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