Как работает " кот
мне нужно написать скрипт для ввода многострочного ввода в программу (psql
).
немного погуглив, я обнаружил, что работает следующий синтаксис:
cat << EOF | psql ---params
BEGIN;
`pg_dump ----something`
update table .... statement ...;
END;
EOF
это правильно строит многострочную строку (от BEGIN;
до END;
, включительно) и передает его как вход в psql
.
но я понятия не имею, как/почему это работает, Может кто-нибудь объяснить?
я имею в виду в основном cat << EOF
Я знаю >
выводит в файл, >>
дописывает в файл <
считывает входные данные из файла.
что значит <<
точно?
и есть ли для этого страница man?
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
.некоторые правила о тегах здесь:
- тег может быть любой строкой, прописной или строчной, хотя большинство людей используют верхний регистр по соглашению.
- тег не будет рассматриваться как здесь тег, если есть другие слова в эта линия. В этом случае он будет просто считаться частью строки. Тег должен быть сам по себе на отдельной строке, чтобы считаться тегом.
- тег не должен иметь передних или конечных пробелов в этой строке, чтобы считаться тегом. В противном случае он будет рассматриваться как часть строки.
пример:
$ 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