Как работает " кот


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

немного погуглив, я обнаружил, что работает следующий синтаксис:

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

`pg_dump ----something`

update table .... statement ...;

END;
EOF

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

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

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

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

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

7 424

7 ответов:

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


С man bash:

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

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

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

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

          <<[-]word
                  here-document
          delimiter

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

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

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

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

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

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

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

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

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

The содержит:

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

3. Пройти многострочные к трубе в bash

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

The содержит 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> символы должны быть удалены из входных строк и строки, содержащей конечный разделитель. Если в строке указано более одного оператора "

когда здесь-документ читается из a терминальное устройство и оболочка являются интерактивными, они должны записывать содержимое переменной 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 вдавливания здесь. Хлоп.

используя тройник вместо кота

не совсем как ответ на исходный вопрос, но я все равно хотел поделиться этим: мне нужно было создать файл конфигурации в каталоге, который требовал прав 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