Làm thế nào tôi có thể viết một di sản vào một tập tin trong tập lệnh Bash?


Câu trả lời:


1073

Đọc Hướng dẫn Bash-Scripting nâng cao Chương 19. Tại đây Tài liệu .

Đây là một ví dụ sẽ ghi nội dung vào một tệp tại /tmp/yourfilehere

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

Lưu ý rằng 'EOF' (The LimitString) cuối cùng không được có bất kỳ khoảng trắng nào trước từ này, vì điều đó có nghĩa làLimitString chí sẽ không được nhận ra.

Trong tập lệnh shell, bạn có thể muốn sử dụng thụt lề để làm cho mã có thể đọc được, tuy nhiên điều này có thể có tác dụng không mong muốn khi thụt văn bản trong tài liệu của bạn ở đây. Trong trường hợp này, sử dụng <<-(theo dấu gạch ngang) để tắt các tab hàng đầu ( Lưu ý rằng để kiểm tra điều này, bạn sẽ cần thay thế khoảng trắng hàng đầu bằng một ký tự tab , vì tôi không thể in các ký tự tab thực tế ở đây.)

#!/usr/bin/env bash

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

Nếu bạn không muốn diễn giải các biến trong văn bản, thì hãy sử dụng dấu ngoặc đơn:

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

Để dẫn ống thông qua một đường ống chỉ huy:

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

Đầu ra:

foo
bbr
bbz

... hoặc để viết di truyền vào một tệp bằng cách sử dụng sudo:

cat <<'EOF' |  sed 's/a/b/' | sudo tee /etc/config_file.conf
foo
bar
baz
EOF

11
Bạn thậm chí không cần Bash, tính năng này cũng có trong các vỏ Bourne / Korn / POSIX.
Janus Troelsen

5
Thế còn <<<, chúng được gọi là gì?
Jürgen Paul

18
@PinnutUndertheSea <<<được gọi là 'Đây String'. Mã như tr a-z A-Z <<< 'one two three'sẽ dẫn đến chuỗi ONE TWO THREE. Thêm thông tin tại en.wikipedia.org/wiki/Here_document#Here_strings
Stefan Lasiewski

8
EOF cuối cùng không nên có bất kỳ khoảng trắng nào sau nó. Ít nhất là trên bash, điều này dẫn đến việc nó không được nhận dạng là dấu phân cách
carpii

10
Vì di truyền cụ thể này được dự định là nội dung theo nghĩa đen, thay vì chứa các thay thế, nên nó <<'EOF'thay vì <<EOF.
Charles Duffy

152

Thay vì sử dụng catvà chuyển hướng I / O, có thể hữu ích khi sử dụng teethay thế:

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

Nó ngắn gọn hơn, cộng với không giống như toán tử chuyển hướng, nó có thể được kết hợp với sudonếu bạn cần ghi vào các tệp có quyền root.


18
Tôi khuyên bạn nên thêm > /dev/nullvào cuối dòng đầu tiên để ngăn nội dung của tệp ở đây được hiển thị thành thiết bị xuất chuẩn khi nó được tạo.
Joe Carroll

11
Đúng, nhưng giải pháp của bạn đã hấp dẫn tôi vì tính tương thích của nó sudo, hơn là vì tính ngắn gọn của nó :-)
Joe Carroll

2
Làm thế nào bạn sẽ sử dụng phương pháp này để chắp thêm vào một tập tin hiện có?
MountainX

5
@MaxX Kiểm tra man tee. Sử dụng -acờ để chắp thêm thay vì ghi đè.
Livven

3
Để sử dụng trong tập lệnh cấu hình mà đôi khi tôi cần giám sát, tôi thích cái này hơn nó in nội dung.
Alois Mahdal

59

Ghi chú:

Câu hỏi (làm thế nào để viết một tài liệu ở đây (còn gọi là heredoc ) vào một tệp trong tập lệnh bash?) Có (ít nhất) 3 kích thước hoặc câu hỏi độc lập chính:

  1. Bạn có muốn ghi đè lên một tệp hiện có, chắp thêm vào một tệp hiện có hoặc ghi vào một tệp mới không?
  2. Người dùng của bạn hoặc người dùng khác (ví dụ root:) sở hữu tệp?
  3. Bạn có muốn viết nội dung của di truyền theo nghĩa đen của bạn, hoặc để bash diễn giải các tham chiếu biến trong di sản của bạn không?

. thiêng liêng về EOF, chỉ cần đảm bảo rằng chuỗi bạn sử dụng làm định danh phân định của bạn không xảy ra bên trong di sản của bạn:

  1. Để ghi đè lên một tệp hiện có (hoặc ghi vào một tệp mới) mà bạn sở hữu, thay thế các tham chiếu biến trong 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. Để nối thêm một tệp hiện có (hoặc ghi vào một tệp mới) mà bạn sở hữu, thay thế các tham chiếu biến trong 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. Để ghi đè một tệp hiện có (hoặc ghi vào một tệp mới) mà bạn sở hữu, với nội dung bằng chữ của di truyền:

    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. Để nối thêm một tệp hiện có (hoặc ghi vào một tệp mới) mà bạn sở hữu, với nội dung theo nghĩa đen của di truyền:

    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. Để ghi đè một tệp hiện có (hoặc ghi vào một tệp mới) thuộc sở hữu của root, thay thế các tham chiếu biến trong 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. Để nối thêm một tệp hiện có (hoặc ghi vào một tệp mới) thuộc sở hữu của user = foo, với nội dung bằng chữ của 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

# 6 là tốt nhất. Nhưng làm thế nào để bạn ghi đè lên nội dung của tệp hiện có với # 6?
Alexanderr Makov

2
@Aleksandr Makov: làm thế nào để bạn ghi đè lên nội dung của tệp hiện có với # 6? Bỏ qua -a== --append; tức là tee -a-> tee. Xem info tee(Tôi sẽ trích dẫn ở đây, nhưng đánh dấu nhận xét quá hạn chế.
TomRoche

1
Có lợi ích gì khi # 6 sử dụng mèo và đường ống để phát bóng thay vì sudo tee /path/to/your/file << 'Screw_you_Foo'?
codemonkee

Tại sao FOEthay vì EOFtrong ví dụ bổ sung?
vẫy tay

2
@becko: chỉ để minh họa rằng nhãn chỉ là nhãn. Lưu ý rằng tôi đã sử dụng một nhãn khác nhau trong mỗi ví dụ.
TomRoche

41

Để xây dựng câu trả lời của @ Livven , đây là một số kết hợp hữu ích.

  1. thay thế biến, tab hàng đầu được giữ lại, ghi đè tập tin, echo vào thiết bị xuất chuẩn

    tee /path/to/file <<EOF
    ${variable}
    EOF
  2. không thay thế biến , giữ lại tab hàng đầu, ghi đè tệp, echo vào thiết bị xuất chuẩn

    tee /path/to/file <<'EOF'
    ${variable}
    EOF
  3. thay thế biến, tab hàng đầu bị xóa , ghi đè tập tin, echo vào thiết bị xuất chuẩn

    tee /path/to/file <<-EOF
        ${variable}
    EOF
  4. thay thế biến, tab hàng đầu được giữ lại, nối vào tệp , echo vào stdout

    tee -a /path/to/file <<EOF
    ${variable}
    EOF
  5. thay thế biến, tab hàng đầu được giữ lại, ghi đè tập tin, không có tiếng vang đến thiết bị xuất chuẩn

    tee /path/to/file <<EOF >/dev/null
    ${variable}
    EOF
  6. ở trên có thể được kết hợp với sudolà tốt

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

16

Khi quyền truy cập được yêu cầu

Khi quyền gốc được yêu cầu cho tệp đích, hãy sử dụng |sudo teethay vì >:

cat << 'EOF' |sudo tee /tmp/yourprotectedfilehere
The variable $FOO will *not* be interpreted.
EOF

Có thể chuyển các biến đến đây tài liệu? Làm thế nào bạn có thể có được nó để $ FOO được giải thích?
dùng1527227

@ user1527227 Như ví dụ ở đây, tệp nói: Biến $ FOO sẽ không được diễn giải.
Serge Stroobandt

Dưới đây tôi đã cố gắng kết hợp và tổ chức câu trả lời này với câu trả lời của Stefan Lasiewski .
TomRoche

3
@ user1527227 Chỉ không bao gồm EOF trong dấu ngoặc đơn. Sau đó $ FOO sẽ được giải thích.
imnd_neel

11

Đối với những người trong tương lai có thể có vấn đề này, định dạng sau đã hoạt động:

(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

6
Đừng cần dấu ngoặc đơn: cat << END > afiletiếp theo là di truyền hoạt động hoàn toàn tốt.
glenn jackman

Cảm ơn, điều này thực sự đã giải quyết một vấn đề khác mà tôi gặp phải. Sau một vài tài liệu ở đây đã có một số vấn đề. Tôi nghĩ rằng nó đã được thực hiện với các parens, như với lời khuyên ở trên nó đã sửa nó.
Joshua Enfield

2
Điều này sẽ không làm việc. Chuyển hướng đầu ra cần ở cuối dòng bắt đầu bằng catcâu trả lời được chấp nhận.
Tạm dừng cho đến khi có thông báo mới.

2
@DennisWilliamson Nó hoạt động, đó là những gì các parens dành cho. Toàn bộ catchạy bên trong một lớp con và tất cả đầu ra của lớp con được chuyển hướng đến tệp
Izkata

2
@Izkata: Nếu bạn nhìn vào lịch sử chỉnh sửa của câu trả lời này, các dấu ngoặc đơn đã bị xóa trước khi tôi đưa ra nhận xét của mình và thêm lại sau đó. áp dụng nhận xét của glenn jackman (và của tôi).
Tạm dừng cho đến khi có thông báo mới.

3

Ví dụ, bạn có thể sử dụng nó:

Đầu tiên (tạo kết nối 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

Thứ hai (thực thi lệnh):

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

Thứ ba (thực thi lệnh):

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 (sử dụng biến):

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

-1

Tôi thích phương pháp này để thu gọn, dễ đọc và trình bày trong một kịch bản thụt lề:

<<-End_of_file >file
       foo bar
End_of_file

Đâu →       là một tabnhân vật.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.