Apakah ada cara untuk mengatur ini untuk semua perintah dalam fungsi / skrip bash?
Alexander Mills
Jawaban:
39
cmd | while read line; do echo "[ERROR] $line"; done
memiliki keunggulan hanya menggunakan bash builtin sehingga lebih sedikit proses akan dibuat / dihancurkan sehingga harus menjadi sentuhan lebih cepat daripada awk atau sed.
@ tzrik menunjukkan bahwa itu mungkin juga membuat fungsi bash yang bagus. Mendefinisikannya seperti:
function prepend() { while read line; do echo "${1}${line}"; done; }
Ini sebenarnya hanya mengurangi jumlah proses per satu. (Tapi itu mungkin akan lebih cepat karena tidak ada regexps ( sed) atau bahkan string yang membelah ( awk) digunakan.)
grawity
BTW, saya ingin tahu tentang kinerja dan di sini adalah hasil dari tolok ukur sederhana saya menggunakan bash, sed dan awk. Mendorong sekitar 1000 baris teks (dmesg output) ke file FIFO dan kemudian membacanya seperti ini: pastebin.ca/1606844 Sepertinya awk adalah pemenangnya. Ada ide mengapa?
Ilya Zakreuski
1
hati-hati menjalankan tes waktu seperti itu - coba jalankan di semua 6 pesanan yang berbeda dan kemudian rata-rata hasilnya. Perintah berbeda untuk mengurangi efek cache dan rata-rata untuk mengurangi efek gangguan / penjadwalan latar belakang.
pjz
Pertanyaan ini ditandai "shell", bukan "bash".
fiatjaf
1
Cukup mudah untuk membungkusnya dalam suatu fungsi juga:function prepend() { while read line; do echo "${1}${line}"; done; }
Anda bisa keluar dari ruang lingkup tanda kutip untuk referensi variabel: cmd | awk '{print "['$V]' " $0}'- ini harus dievaluasi sekali pada awal, jadi tidak ada overhead kinerja.
robert
13
Dengan segala penghargaan kepada @grawity, saya mengirimkan komentarnya sebagai jawaban, karena sepertinya ini jawaban terbaik bagi saya.
Saya kira itu tergantung pada tujuan Anda. Jika tujuan Anda adalah dengan hanya menambahkan ke setiap baris dalam file, ini mencapai tujuan itu dengan sangat sedikit karakter, menggunakan alat yang sangat akrab. Saya jauh lebih suka itu untuk skrip bash 10 baris. The awksatu-kapal ini cukup bagus, tapi saya pikir bahwa lebih banyak orang yang akrab dengan seddari awk. Skrip bash baik untuk fungsinya, tetapi tampaknya ia menjawab pertanyaan yang tidak ditanyakan.
Eric Wilson
Jawaban yang diajukan pjz juga bagus sekali. Itu bukan program tambahan, proses dan mungkin berjalan sedikit lebih cepat.
user14645
3
sed X cmdmembaca cmddan tidak menjalankannya. Entah cmd | sed 's/^/[ERROR] /'atau sed 's/^/[ERROR] /' <(cmd)atau cmd > >(sed 's/^/[ERROR] /'). Namun waspadalah terhadap yang terakhir. Bahkan bahwa ini memungkinkan Anda untuk mengakses nilai kembali dari cmdyang sedberjalan di latar belakang, sehingga kemungkinan Anda melihat output setelah cmd selesai. Bagus untuk masuk ke file. Dan perhatikan bahwa awkmungkin lebih cepat dari sed.
Tino
Bagus. Perintah ini mudah alias. alias lpad="sed 's/^/ /'". bukannya ERROR saya memasukkan 4 spasi utama. Sekarang, untuk trik sulap: ls | lpad | pbcopyakan menambahkan ls output dengan 4 spasi yang menandainya sebagai Penurunan harga untuk kode , yang berarti bahwa Anda menempelkan clipboard ( pbcopy ambil, pada mac) langsung ke StackOverflow atau konteks penurunan harga lainnya. Tidak bisa aliasdengan awk jawaban (pada tanggal 1 try) jadi ini salah satu menang. Solusi sambil membaca juga alias-mampu, tetapi saya menemukan sed ini lebih ekspresif.
JL Peyret
8
Saya membuat repositori GitHub untuk melakukan beberapa tes kecepatan.
Hasilnya adalah:
Dalam kasus umum, awkini tercepat. sedsedikit lebih lambat dan perltidak lebih lambat dari sed. Rupanya, semua itu adalah bahasa yang sangat optimal untuk pemrosesan teks.
Dalam situasi yang sangat khusus, di mana garpu mendominasi, menjalankan skrip Anda sebagai skrip yang dikompilasi ksh( shcomp) dapat menghemat waktu pemrosesan lebih banyak. Sebaliknya, bashmati lambat dibandingkan dengan kshskrip yang dikompilasi .
Membuat biner yang terhubung secara statis untuk dikalahkan awktampaknya tidak sepadan dengan usaha.
Sebaliknya pythonsangat lambat, tetapi saya belum menguji case yang dikompilasi, karena biasanya bukan apa yang akan Anda lakukan dalam case scripting seperti itu.
Varian berikut diuji:
while read line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST]" $line; done
while read -r line; do echo "[TEST]" "$line"; done
sed 's/^/[TEST] /'
awk '{ print "[TEST] " $0 }'
awk -vT="[TEST] " '{ print T $0 }'
awk -vT="[TEST]" '{ print T " " $0 }'
awk -vT="[TEST]" 'BEGIN { T=T " "; } { print T $0 }'
T="[TEST] " awk '{ print ENVIRON["T"] $0 }'
T="[TEST]" awk '{ print ENVIRON["T"] " " $0 }'
T="[TEST]" awk 'BEGIN { T=ENVIRON["T"] " " } { print T $0 }'
perl -ne 'print "[TEST] $_"'
Dua varian biner dari salah satu alat saya (meskipun tidak dioptimalkan untuk kecepatan):
Saya menginginkan solusi yang menangani stdout dan stderr, jadi saya menulis prepend.shdan meletakkannya di jalur saya:
#!/bin/bash
prepend_lines(){
local prepended=$1
while read line; do
echo "$prepended" "$line"
done
}
tag=$1
shift
"$@" > >(prepend_lines "$tag") 2> >(prepend_lines "$tag" 1>&2)
Sekarang saya bisa menjalankan prepend.sh "[ERROR]" cmd ..., untuk menambahkan "[KESALAHAN]" ke output cmd, dan masih memiliki stderr dan stdout terpisah.
Saya mencoba pendekatan ini tetapi ada sesuatu yang terjadi dengan >(subkulit yang tidak bisa saya selesaikan. Tampaknya skrip itu selesai, dan hasilnya tiba ke terminal setelah prompt kembali yang agak berantakan. Saya akhirnya datang dengan jawaban di sini stackoverflow.com/a/25948606/409638
Jawaban:
memiliki keunggulan hanya menggunakan bash builtin sehingga lebih sedikit proses akan dibuat / dihancurkan sehingga harus menjadi sentuhan lebih cepat daripada awk atau sed.
@ tzrik menunjukkan bahwa itu mungkin juga membuat fungsi bash yang bagus. Mendefinisikannya seperti:
akan memungkinkannya digunakan seperti:
sumber
sed
) atau bahkan string yang membelah (awk
) digunakan.)function prepend() { while read line; do echo "${1}${line}"; done; }
Coba ini:
Tepuk tangan
sumber
awk -vT="[ERROR] " '{ print T $0 }'
atauawk -vT="[ERROR]" '{ print T " " $0 }'
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'
atauT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
cmd | awk '{print "['$V]' " $0}'
- ini harus dievaluasi sekali pada awal, jadi tidak ada overhead kinerja.Dengan segala penghargaan kepada @grawity, saya mengirimkan komentarnya sebagai jawaban, karena sepertinya ini jawaban terbaik bagi saya.
sumber
awk
satu-kapal ini cukup bagus, tapi saya pikir bahwa lebih banyak orang yang akrab dengansed
dariawk
. Skrip bash baik untuk fungsinya, tetapi tampaknya ia menjawab pertanyaan yang tidak ditanyakan.sed X cmd
membacacmd
dan tidak menjalankannya. Entahcmd | sed 's/^/[ERROR] /'
ataused 's/^/[ERROR] /' <(cmd)
ataucmd > >(sed 's/^/[ERROR] /')
. Namun waspadalah terhadap yang terakhir. Bahkan bahwa ini memungkinkan Anda untuk mengakses nilai kembali daricmd
yangsed
berjalan di latar belakang, sehingga kemungkinan Anda melihat output setelah cmd selesai. Bagus untuk masuk ke file. Dan perhatikan bahwaawk
mungkin lebih cepat darised
.alias lpad="sed 's/^/ /'"
. bukannya ERROR saya memasukkan 4 spasi utama. Sekarang, untuk trik sulap:ls | lpad | pbcopy
akan menambahkan ls output dengan 4 spasi yang menandainya sebagai Penurunan harga untuk kode , yang berarti bahwa Anda menempelkan clipboard ( pbcopy ambil, pada mac) langsung ke StackOverflow atau konteks penurunan harga lainnya. Tidak bisaalias
dengan awk jawaban (pada tanggal 1 try) jadi ini salah satu menang. Solusi sambil membaca juga alias-mampu, tetapi saya menemukan sed ini lebih ekspresif.Saya membuat repositori GitHub untuk melakukan beberapa tes kecepatan.
Hasilnya adalah:
awk
ini tercepat.sed
sedikit lebih lambat danperl
tidak lebih lambat darised
. Rupanya, semua itu adalah bahasa yang sangat optimal untuk pemrosesan teks.ksh
(shcomp
) dapat menghemat waktu pemrosesan lebih banyak. Sebaliknya,bash
mati lambat dibandingkan denganksh
skrip yang dikompilasi .awk
tampaknya tidak sepadan dengan usaha.Sebaliknya
python
sangat lambat, tetapi saya belum menguji case yang dikompilasi, karena biasanya bukan apa yang akan Anda lakukan dalam case scripting seperti itu.Varian berikut diuji:
Dua varian biner dari salah satu alat saya (meskipun tidak dioptimalkan untuk kecepatan):
Python buffered:
Dan Python tidak ditemukan:
sumber
awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'
untuk mengeluarkan stempel waktusumber
sed 's/^/[ERROR] /'
Saya menginginkan solusi yang menangani stdout dan stderr, jadi saya menulis
prepend.sh
dan meletakkannya di jalur saya:Sekarang saya bisa menjalankan
prepend.sh "[ERROR]" cmd ...
, untuk menambahkan "[KESALAHAN]" ke outputcmd
, dan masih memiliki stderr dan stdout terpisah.sumber
>(
subkulit yang tidak bisa saya selesaikan. Tampaknya skrip itu selesai, dan hasilnya tiba ke terminal setelah prompt kembali yang agak berantakan. Saya akhirnya datang dengan jawaban di sini stackoverflow.com/a/25948606/409638