Как я могу записать heredoc в файл в скрипте Bash?

621

Как я могу записать документ здесь в файл в Bash script?

Теги:
heredoc

8 ответов

861
Лучший ответ

Прочтите расширенный Bash -Scripting Guide Глава 19. Здесь Документы.

Вот пример, который будет записывать содержимое в файл в /tmp/yourfilehere

cat << EOF > /tmp/yourfilehere
These contents will be written to the file.
        This line is indented.
EOF

Обратите внимание, что окончательный "EOF" (The LimitString) не должен иметь пробелов перед словом, потому что это означает, что LimitString не будет распознан.

В оболочке script вы можете использовать отступы, чтобы сделать код читаемым, однако это может иметь нежелательный эффект отступов текста внутри вашего документа. В этом случае используйте <<- (за которым следует тире), чтобы отключить основные вкладки (Примечание), чтобы проверить это, вам нужно заменить ведущие пробелы символом табуляции, так как я не могу напечатать фактические символы табов здесь.)

#!/usr/bin/env bash

if true ; then
    cat <<- EOF > /tmp/yourfilehere
    The leading tab is ignored.
    EOF
fi

Если вы не хотите интерпретировать переменные в тексте, используйте одинарные кавычки:

cat << 'EOF' > /tmp/yourfilehere
The variable $FOO will not be interpreted.
EOF

Чтобы передать heredoc через конвейер команд:

cat <<'EOF' |  sed 's/a/b/'
foo
bar
baz
EOF

Вывод:

foo
bbr
bbz

... или записать heredoc в файл с помощью sudo:

cat <<'EOF' |  sed 's/a/b/' | sudo tee /etc/config_file.conf
foo
bar
baz
EOF
  • 10
    Вам даже не нужен Bash, эта функция есть и в оболочках Bourne / Korn / POSIX.
  • 5
    как насчет <<< , как они называются?
Показать ещё 10 комментариев
119

Вместо использования cat и перенаправления ввода/вывода было бы полезно использовать tee вместо этого:

tee newfile <<EOF
line 1
line 2
line 3
EOF

Это более краткий, плюс в отличие от оператора перенаправления его можно комбинировать с sudo, если вам нужно писать в файлы с правами root.

  • 15
    Я бы предложил добавить > /dev/null в конце первой строки, чтобы содержимое этого файла не отображалось на stdout при его создании.
  • 0
    Приятно спасибо! Хотя это сводит на нет некоторую краткость использования tee в первую очередь, я думаю.
Показать ещё 4 комментария
46

Замечания:

Вопрос (как написать документ здесь (aka heredoc) в файл в сценарии bash?) Имеет (по крайней мере) 3 основных независимых измерения или подзапросы:

  1. Вы хотите перезаписать существующий файл, добавить в существующий файл или записать в новый файл?
  2. У вашего пользователя или другого пользователя (например, root) есть файл?
  3. Вы хотите написать содержание своего heredoc буквально или интерпретировать переменные bash в вашем heredoc?

(Существуют другие измерения/подзапросы, которые я не считаю важными. Рассмотрите возможность редактирования этого ответа, чтобы добавить их!) Вот некоторые из наиболее важных комбинаций измерений перечисленного выше вопроса с различными разграничивающими идентификаторами - нет ничего священный об EOF, просто убедитесь, что строка, которую вы используете в качестве идентификатора разграничения, не встречается внутри вашего heredoc:

  1. Чтобы перезаписать существующий файл (или записать в новый файл), который у вас есть, замените ссылки переменных внутри heredoc:

    cat << EOF > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    EOF
    
  2. Чтобы добавить существующий файл (или записать в новый файл), который у вас есть, замените ссылки переменных внутри heredoc:

    cat << FOE >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    FOE
    
  3. Чтобы перезаписать существующий файл (или записать в новый файл), который у вас есть, с буквальным содержимым heredoc:

    cat << 'END_OF_FILE' > /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    END_OF_FILE
    
  4. Чтобы добавить существующий файл (или записать в новый файл), который у вас есть, с буквальным содержимым heredoc:

    cat << 'eof' >> /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    eof
    
  5. Чтобы перезаписать существующий файл (или записать в новый файл), принадлежащий root, подставляя ссылки на переменные внутри heredoc:

    cat << until_it_ends | sudo tee /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, with the variable contents substituted.
    until_it_ends
    
  6. Чтобы добавить существующий файл (или записать в новый файл), принадлежащий пользователю = foo, с буквальным содержимым heredoc:

    cat << 'Screw_you_Foo' | sudo -u foo tee -a /path/to/your/file
    This line will write to the file.
    ${THIS} will also write to the file, without the variable contents substituted.
    Screw_you_Foo
    
  • 0
    № 6 самый лучший. Но как перезаписать содержимое существующего файла с # 6?
  • 1
    @ Александр Маков: как перезаписать содержимое существующего файла # 6? --append -a == --append ; т.е. tee -a -> tee . Смотрите info tee (я бы процитировал это здесь, но разметка комментариев слишком ограничена.
Показать ещё 3 комментария
19

Чтобы построить на @Livven answer, вот несколько полезных комбинаций.

  • подстановка переменных, ведущая вкладка сохранена, перезаписывает файл, echo to stdout

    tee /path/to/file <<EOF
    ${variable}
    EOF
    
  • нет подстановки переменных, ведущая вкладка сохраняется, перезаписывает файл, echo to stdout

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
    
  • подстановка переменных, удалена ведущая вкладка, перезаписать файл, echo to stdout

    tee /path/to/file <<-EOF
        ${variable}
    EOF
    
  • подстановка переменных, верхняя вкладка сохранена, добавить в файл, echo to stdout

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
    
  • подстановка переменных, ведущая вкладка сохранена, перезаписать файл, нет эха в stdout

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
    
  • приведенное выше можно объединить с sudo, а также

    sudo -u USER tee /path/to/file <<EOF
    ${variable}
    EOF
    
15

Если требуются права root

Если для файла назначения требуются права root, используйте |sudo tee вместо >:

cat << 'EOF' |sudo tee /tmp/yourprotectedfilehere
The variable $FOO will *not* be interpreted.
EOF
  • 0
    Можно ли передавать переменные в документы здесь? Как ты мог получить это так, что $ FOO был интерпретирован?
  • 0
    @ user1527227 Как показано в файле примера: переменная $ FOO интерпретироваться не будет.
Показать ещё 2 комментария
12

Для будущих людей, которые могут иметь эту проблему, работал следующий формат:

(cat <<- _EOF_
        LogFile /var/log/clamd.log
        LogTime yes
        DatabaseDirectory /var/lib/clamav
        LocalSocket /tmp/clamd.socket
        TCPAddr 127.0.0.1
        SelfCheck 1020
        ScanPDF yes
        _EOF_
) > /etc/clamd.conf
  • 5
    Не нужно скобки: cat << END > afile за которым следует heredoc, работает отлично.
  • 0
    Спасибо, это фактически решило другую проблему, с которой я столкнулся. После нескольких документов здесь возникли некоторые проблемы. Я думаю, что это имеет отношение к паренсу, поскольку с советом выше это исправило это.
Показать ещё 3 комментария
2

В качестве примера вы можете использовать его:

Сначала (создание ssh-соединения):

while read pass port user ip files directs; do
    sshpass -p$pass scp -o 'StrictHostKeyChecking no' -P $port $files $user@$ip:$directs
done <<____HERE
    PASS    PORT    USER    IP    FILES    DIRECTS
      .      .       .       .      .         .
      .      .       .       .      .         .
      .      .       .       .      .         .
    PASS    PORT    USER    IP    FILES    DIRECTS
____HERE

Второй (выполнение команд):

while read pass port user ip; do
    sshpass -p$pass ssh -p $port $user@$ip <<ENDSSH1
    COMMAND 1
    .
    .
    .
    COMMAND n
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP
      .      .       .       .
      .      .       .       .
      .      .       .       .
    PASS    PORT    USER    IP    
____HERE

Третий (выполнение команд):

Script=$'
#Your commands
'

while read pass port user ip; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip "$Script"

done <<___HERE
PASS    PORT    USER    IP
  .      .       .       .
  .      .       .       .
  .      .       .       .
PASS    PORT    USER    IP  
___HERE

Forth (с использованием переменных):

while read pass port user ip fileoutput; do
    sshpass -p$pass ssh -o 'StrictHostKeyChecking no' -p $port $user@$ip fileinput=$fileinput 'bash -s'<<ENDSSH1
    #Your command > $fileinput
    #Your command > $fileinput
ENDSSH1
done <<____HERE
    PASS    PORT    USER    IP      FILE-OUTPUT
      .      .       .       .          .
      .      .       .       .          .
      .      .       .       .          .
    PASS    PORT    USER    IP      FILE-OUTPUT
____HERE
0

Мне нравится этот метод для получения четкости, удобочитаемости и представления в отступом:

<<-End_of_file >file
→       foo bar
End_of_file

Где - символ tab.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню