Bagaimana Anda menggunakan redirection output dalam kombinasi dengan dokumen dan kucing di sini?

56

Katakanlah saya memiliki skrip yang ingin saya pipekan ke perintah lain atau redirect ke file (piping ke shuntuk contoh). Asumsikan saya menggunakan bash.

Saya bisa melakukannya dengan menggunakan echo:

echo "touch somefile
echo foo > somefile" | sh

Saya juga bisa melakukan hal yang hampir sama menggunakan cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

Tetapi jika saya mengganti "EOF" dengan "EOF | sh" itu hanya berpikir bahwa itu adalah bagian dari heredoc.

Bagaimana saya bisa membuatnya sehingga catmengeluarkan teks dari stdin, dan kemudian mengirimnya ke lokasi yang sewenang-wenang?

strugee
sumber
touchadalah kecuali di sana, apa yang sebenarnya Anda inginkan? baru saja membaca file input dan mengarahkan ke yang lain dengan stdout?
Rahul Patil
2
@RahulPatil tentu saja tidak berguna. Saya hanya ingin contoh dengan lebih dari satu baris, untuk menggambarkan heredoc dengan lebih baik. Dan lihat contoh menggunakan echo- Saya bertanya-tanya apa yang setara akan menggunakan cat.
strugee
Contoh Anda membuat shskrip dari banyak string dan meneruskannya langsung ke sh. Saya menemukan Q Anda mencari lewat keluaran teks dari beberapa perintah, termasuk dokumen DI SINI, langsung ke perintah. Itulah yang dilakukan oleh contoh kedua jawaban Ash.
Dave X

Jawaban:

91

Ada beberapa cara untuk melakukan ini. Mungkin yang paling sederhana adalah ini:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

Lain, yang sintaksisnya lebih bagus menurut saya:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

Ini berfungsi juga, tetapi tanpa subkulit:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

Lebih banyak variasi:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

Atau:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

By the way, saya berharap penggunaan catdalam pertanyaan Anda adalah pengganti untuk sesuatu yang lain. Jika tidak, keluarkan, seperti ini:

sh <<EOF
touch somefile
echo foo > somefile
EOF

Yang bisa disederhanakan menjadi ini:

sh -c 'touch somefile; echo foo > somefile'

atau:

sh -c 'touch somefile
echo foo > somefile'

Mengarahkan output, bukan perpipaan

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

Menggunakan catuntuk mendapatkan yang setara dengan echo test > out:

cat >out <<EOF
test
EOF

Dokumen Berganda Di Sini

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

Ini menghasilkan output:

hi
---
there

Inilah yang terjadi:

  • Shell melihat ( ... )dan menjalankan perintah terlampir dalam sebuah subkulit.
  • Kucing dan gema cukup sederhana. The cat <&3mengatakan untuk menjalankan kucing dengan deskriptor file (fd) 0 (stdin) diarahkan dari fd 3; dengan kata lain, keluarkan input dari fd 3.
  • Sebelum (...)dimulai, shell melihat dua di sini dokumen pengalihan dan pengganti fd 0 ( <<EOF) dan fd 3 ( 3<<EOF2) dengan sisi baca pipa
  • Setelah perintah awal dimulai, shell membaca stdin-nya sampai EOF tercapai dan mengirimkannya ke sisi penulisan dari pipa pertama
  • Selanjutnya, ia melakukan hal yang sama dengan EOF2 dan sisi penulisan dari pipa kedua
Abu
sumber
diberikan contoh kedua hingga terakhir, dapatkah Anda memberikan contoh dengan pengalihan stdout alih-alih perpipaan?
strugee
Saya mengedit jawaban dengan contoh pengalihan; apakah ini bentuk yang ingin Anda edit? Jika tidak, bisakah Anda memberikan baris pertama bagian itu untuk menjelaskan?
ash
1
Mungkin membantu untuk memahami bagaimana shell memproses ini. Ketika mengevaluasi baris perintah dan menemukan << EOF, itu kemudian membaca dari input standar sampai salah satu baris dengan hanya EOF ditemukan, atau end-of-input. Segala sesuatu yang lain pada baris perintah asli yang belum diproses kemudian terus diproses. Jadi, misalnya, dimungkinkan untuk melakukan sesuatu seperti ini: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >outdan kemudian berikan input perintah dengan dua blok di sini secara berurutan.
ash
Penjelasan Anda tentang pemrosesan shell itu menarik tetapi di atas kepala saya :) Apa yang ingin saya ketahui adalah apa yang akan catsetara echo test > outdengan menggunakan heredoc. Sedangkan contoh yang Anda berikan menambahkan pengalihan di ujung pipa.
strugee
1
@OlivierDulac - Saya menambahkan beberapa contoh heredoc ke jawabannya.
ash
1

Saya hanya ingin menunjukkan bahwa menggunakan meowsama validnya dengan EOF.

Script ini akan ditambahkan Meow!ke file bernama cat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

Simpan sebagai catsdan buat itu dapat dieksekusi dengan chmod +x cats, lalu jalankan dengan ./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

Penjelasan:

  • cat <<meowadalah sintaks dokumen di sini . Itu menginstruksikan skrip untuk mengambil blok teks yang mengikuti baris ini, sampai bertemu string meow. Konten kemudian akan dikeluarkan (atau disalurkan bersama).
  • >> catpipa ke file bernama cat.
  • Menggunakan >alih-alih >>akan menimpa file alih-alih menambahkannya.
  • Meow!adalah isi dari dokumen di sini .
  • meowadalah penanda akhir untuk dokumen di sini . Isi, dengan penggunaan >>, ditambahkan ke cat.

Memipis ke stdout dan ke file:

Untuk melakukan pemipaan yang Anda minta, tidak ada dokumen yang diperlukan di sini.

cattidak dapat menghasilkan teks dan meneruskan teks, tetapi teesangat cocok untuk apa yang Anda minta:

echo echo | tee tee

Ini akan menghasilkan string echodan menulis echoke file bernama tee.

Anda juga dapat melewati output cat, jika itu adalah bagian dari persyaratan, baik dengan:

echo echo | tee tee | cat </dev/stdin

Atau hanya:

echo echo | tee tee | cat

Isi file:

$ cat tee
echo
Alexander
sumber
1
Ini tidak benar-benar menjawab pertanyaan. Juga >tidak membuat pipa seperti yang ditunjukkan oleh peluru terakhir Anda.
strugee
2
@ strugee, >dapat membuat pipa zshketika fd yang sama dialihkan beberapa kali seperti di echo foo >&1 > teeatau echo foo > tee | cat, di mana zshmengimplementasikan internal teeuntuk memberi makan output echountuk keduanya catdan teefile.
Stéphane Chazelas
Memperbarui jawaban saya untuk menjawab pertanyaan dengan lebih baik.
Alexander