Pertimbangkan skrip ini:
tmpfile=$(mktemp)
cat <<EOS > "$tmpfile"
line 1
line 2
line 3
EOS
cat <(tail -1 "$tmpfile") "$tmpfile"
Ini berfungsi dan menghasilkan:
line 3
line 1
line 2
line 3
Katakanlah sumber input kami, alih-alih menjadi file aktual, malah stdin:
cat <<EOS | # what goes here now?
line 1
line 2
line 3
EOS
Bagaimana kita memodifikasi perintah:
cat <(tail -1 "$tmpfile") "$tmpfile"
Sehingga masih menghasilkan output yang sama, dalam konteks yang berbeda ini?
CATATAN: Heredoc spesifik yang saya lakukan, serta penggunaan Heredoc sendiri, hanyalah ilustrasi. Setiap jawaban yang dapat diterima harus berasumsi bahwa ia menerima data sewenang-wenang melalui stdin .
Jawaban:
Mencoba:
Contoh
Tentukan variabel dengan input kami:
Jalankan perintah kami:
Atau, tentu saja, kita bisa menggunakan di sini-doc:
Bagaimana itu bekerja
x=x $0 ORS
Ini menambahkan setiap baris input ke variabel
x
.Dalam awk,
ORS
adalah pemisah catatan output . Secara default, ini adalah karakter baris baru.END{printf "%s", $0 ORS x}
Setelah kita membaca di seluruh file, ini akan mencetak baris terakhir
$0
,, diikuti oleh isi dari keseluruhan filex
,.Karena ini membaca seluruh input ke dalam memori, itu tidak akan sesuai untuk input besar ( misalnya gigabyte).
sumber
tee
itu, tetapi dari stdin dan file, kita akan memipatkan stdin yang sama menjadi dua proses penggantian yang berbeda. atau apa pun yang kira-kira setara dengan itu?Jika stdin menunjuk ke file yang dapat dicari (seperti dalam kasus bash (tetapi tidak semua shell lainnya) di sini dokumen yang diimplementasikan dengan file temp), Anda bisa mendapatkan ekornya dan kemudian mencari kembali sebelum membaca konten lengkap:
mencari operator tersedia di
zsh
atauksh93
shells, atau bahasa scripting seperti tcl / perl / python, tetapi tidak dibash
. Tetapi Anda selalu dapat memanggil penerjemah yang lebih canggih dari itubash
jika Anda harus menggunakannyabash
.Atau
Sekarang, itu tidak akan berfungsi ketika stdin menunjuk ke file yang tidak dapat dicari seperti pipa atau soket. Kemudian, satu-satunya pilihan adalah membaca dan menyimpan (dalam memori atau dalam file sementara ...) seluruh input.
Beberapa solusi untuk menyimpan dalam memori telah diberikan.
Dengan tempfile, with
zsh
, Anda bisa melakukannya dengan:Jika di Linux, dengan
bash
atauzsh
atau shell apa pun yang menggunakan file temp untuk dokumen di sini, Anda sebenarnya bisa menggunakan file temp yang dibuat oleh dokumen di sini untuk menyimpan output:sumber
Masalah dengan menerjemahkan ini ke sesuatu yang menggunakan
tail
adalah yangtail
perlu membaca seluruh file untuk menemukan akhir. Untuk menggunakannya dalam pipa Anda, Anda harus melakukannyatail
.cat
.Agak sulit bukan untuk menduplikasi konten dokumen (
tee
melakukan itu) tetapi untuk mendapatkan hasil yangtail
akan terjadi sebelum sisa dokumen dikeluarkan, tanpa menggunakan file sementara perantara.Menggunakan
sed
(atauawk
, seperti yang dilakukan John1024 ) menghilangkan penguraian ganda data dan masalah pemesanan dengan menyimpan data dalam memori.The
sed
solusi yang saya usulkan adalah untuk1{h;d;}
, simpan baris pertama di ruang tunggu, apa adanya, dan lewati ke baris berikutnya.H
, tambahkan satu sama lain baris ke ruang penahanan dengan baris baru tertanam.${G;p;}
, tambahkan ruang penyimpanan ke baris terakhir dengan baris baru yang disematkan dan cetak data yang dihasilkan.Ini adalah terjemahan harfiah dari solusi John1024 ke dalam
sed
, dengan peringatan bahwa standar POSIX hanya menjamin bahwa ruang penahanan setidaknya 8192 byte (8 KiB; tetapi merekomendasikan bahwa buffer ini dialokasikan secara dinamis dan diperluas sesuai kebutuhan, yang kedua GNUsed
dan BSDsed
sedang melakukan).Jika Anda membiarkan diri Anda menggunakan pipa bernama:
Ini digunakan
tee
untuk mengirim data ke bawahmypipe
dan pada saat yang samacat
. Thecat
utilitas pertama akan membaca output daritail
(yang berbunyi darimypipe
, yangtee
menulis untuk), dan kemudian menambahkan salinan dokumen yang datang langsung daritee
.Ada kesalahan serius dalam hal ini, dalam hal jika dokumen terlalu besar (lebih besar dari ukuran buffer pipa),
tee
tulisan kemypipe
dancat
akan memblokir sambil menunggu pipa (tanpa nama) kosong. Itu tidak akan dikosongkan sampaicat
dibaca darinya.cat
tidak akan membaca dari itu sampaitail
selesai. Dantail
tidak akan selesai sampaitee
selesai. Ini adalah situasi kebuntuan klasik.Variasi
memiliki masalah yang sama.
sumber
sed
tidak berfungsi jika input hanya memiliki satu baris (mungkinsed '1h;1!H;$!d;G'
). Perhatikan juga bahwa beberapased
implementasi memiliki batas rendah pada ukuran pola dan ruang penyimpanan.Ada alat yang disebutkan
pee
dalam kumpulan utilitas baris perintah yang biasanya dikemas dengan nama "moreutils" (atau dapat diambil dari situs web asalnya ).Jika Anda dapat memilikinya di sistem Anda, maka yang setara untuk contoh Anda akan seperti:
Memesan perintah yang dijalankan
pee
adalah penting karena dieksekusi dalam urutan yang disediakan.sumber
Mencoba:
Karena semuanya adalah data literal ("dokumen yang ada di sini"), dan perbedaan antara itu dan output yang diinginkan adalah sepele, hanya memijat data literal di sana untuk mencocokkan dengan output.
Sekarang anggap
line 3
berasal dari suatu tempat dan disimpan dalam variabel yang disebutlastline
:Dalam dokumen di sini, kita dapat menghasilkan teks dengan mengganti variabel. Tidak hanya itu tetapi kita dapat menghitung teks menggunakan substitusi perintah:
Kami dapat menginterpolasi banyak baris:
Secara umum, hindari pemrosesan teks templat dokumen di sini; cobalah untuk membuatnya menggunakan kode interpolasi.
sumber
cat <<EOS...
OP itu hanya contoh standin untuk "capping file arbitrary," untuk membuat posting spesifik dan pertanyaan menjadi jelas. Apakah itu benar-benar tidak jelas bagi Anda, atau apakah Anda hanya berpikir akan pintar untuk menafsirkan pertanyaan itu secara harfiah?Jika Anda tidak peduli dengan pesanan. Maka ini akan berhasil
cat lines | tee >(tail -1)
. Seperti yang dikatakan orang lain. Anda perlu membaca file dua kali, atau buffer seluruh file, untuk melakukannya dalam urutan yang Anda minta.sumber