Her satıra dize hazırlama komutu?


36

Böyle bir şey mi arıyorsunuz? Herhangi bir fikir?

cmd | prepend "[ERRORS] "

[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc

Bunu bash işlevi / betiğindeki tüm komutlar için ayarlamanın bir yolu var mı?
Alexander Mills,

Yanıtlar:


39
cmd | while read line; do echo "[ERROR] $line"; done

yalnızca bash yerleşiklerini kullanma avantajına sahiptir, bu yüzden daha az işlem yaratılır / yok edilir, bu nedenle awk veya sed'den daha hızlı bir dokunuş olmalıdır .

@tzrik, aynı zamanda hoş bir bash işlevi yaratabileceğinin altını çiziyor. Gibi tanımlanması:

function prepend() { while read line; do echo "${1}${line}"; done; }

gibi kullanılmasına izin verirdi:

cmd | prepend "[ERROR] "

4
Bu aslında işlem sayımını sadece bir azaltmaktadır. (Ama daha hızlı olabilir çünkü regexps ( sed) veya string awk
stringting

BTW, performansı merak ediyordum ve işte bash, sed ve awk kullanan basit kriterlerimin sonuçları. FIFO dosyasına yaklaşık 1000 satır metin (dmesg çıktı) bastırıyor ve ardından bunları şöyle okuyor: pastebin.ca/1606844 awk galibi görünüyor. Neden bir fikrin var mı?
Ilya Zakreuski

1
Böyle zamanlama testlerini yaparken dikkatli olun - bunları 6 farklı siparişte çalıştırmayı ve sonuçların ortalamasını almayı deneyin. Blok önbellek efektlerini azaltmak için farklı siparişler ve arka plan kesintisini / zamanlama efektlerini azaltmak için ortalama.
pjz

Bu soru "bash" değil, "kabuk" olarak etiketlenir.
fiatjaf

1
Aynı zamanda bir fonksiyonla sarması kolay:function prepend() { while read line; do echo "${1}${line}"; done; }
tzrlk

46

Bunu dene:

cmd | awk '{print "[ERROR] " $0}'

Şerefe


1
Bunun dezavantajı, "[ERROR]" değişken olamaz çünkü tüm ifadenin tek tırnak içinde olması gerekir.
user1071136

4
awk -vT="[ERROR] " '{ print T $0 }'veyaawk -vT="[ERROR]" '{ print T " " $0 }'
Tino

2
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'veyaT="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
Tino,

Değişkeni cmd | awk '{print "['$V]' " $0}'serbest bırakmak için tırnak işaretlerinin kapsamından çıkabilirsiniz: - bu başlangıçta bir kez değerlendirilmelidir, bu nedenle performans ek yükü yoktur.
robert

13

@Grawity'ye verdiğim tüm krediyle, yorumunu burada bana en iyi cevap olarak göründüğü gibi, bir cevap olarak gönderiyorum.

sed 's/^/[ERROR] /' cmd

Neden bu bash çözümüne tercih edilir?
user14645,

1
Sanırım amacına bağlı. Amacınız bir dosyadaki her satırı basitçe hazırlamaksa, bu amaç çok aşina olunan bir araç kullanarak çok az karakterle gerçekleştirilir. Bunu 10 satır bash betiğine tercih ediyorum. Tek awkastar yeterince güzel, ama bence daha çok insanın aşina sedolduğu awk. Bash betiği ne yaptığı için iyidir, ancak sorulmamış bir soruyu cevaplıyor gibi görünüyor.
Eric Wilson

PJZ'nin verdiği cevap aynı zamanda hoş bir tek gömlek. O, değil ek programlar yapar işler ve olabilecek çabuk biraz bitkin.
user14645

3
sed X cmdokur cmdve yürütmez. Ya cmd | sed 's/^/[ERROR] /'da sed 's/^/[ERROR] /' <(cmd)ya da cmd > >(sed 's/^/[ERROR] /'). Ancak ikincisine dikkat edin. Bu dönüş değerini erişmeye olanak Hatta bu büyük olasılıkla size çıktı görmeleri için, arka planda çalışır sonra bitmiş cmd. Yine de bir dosyaya giriş yapmak için iyi. Ve muhtemelen daha hızlı olduğunu unutmayın . cmdsedawksed
Tino,

Güzel. Bu komut kolayca takma addır. alias lpad="sed 's/^/ /'". ERROR yerine 4 tane öncü boşluk ekliyorum. Şimdi, sihir numarası için: ls | lpad | pbcopyls çıktısını kod için Markdown olarak işaretleyen 4 boşlukla hazırlayacak , yani panoyu ( pbcopy mac'lardan tutuyor) doğrudan StackOverflow veya başka bir markdown bağlamına yapıştıracağınız anlamına gelecek . Olabilir değil awk bu bir galibiyet böylece (1 denemede) cevap. İse okuma çözüm ayrıca takma-yapabiliyor, ama bunu buldum sed daha etkileyici. alias
JL Peyret

8

Bazı hız testleri yapmak için bir GitHub deposu oluşturdum .

Sonuç:

  • Genel durumda, awken hızlıdır. sedbiraz daha yavaş ve biraz daha perlyavaş değil sed. Görünüşe göre, hepsi bu metin işleme için son derece optimize edilmiş dillerdir.
  • Çatalların baskın olduğu çok özel durumlarda, komut dosyanızı derlenmiş bir kshkomut dosyası ( shcomp) olarak çalıştırmak daha fazla işlem süresi kazandırabilir. Buna karşılık, bashderlenmiş kshkomut dosyalarına göre daha yavaş .
  • Atmak için statik olarak bağlı bir ikili yaratma awkçabaya değmez gibi görünüyor.

Aksine python, yavaş yavaş, ama derlenmiş bir olayı test etmedim, çünkü genellikle böyle bir senaryo durumunda yapabileceğin bir şey değil.

Aşağıdaki değişkenler test edilmiştir:

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] $_"'

Araçlarımdan birinin iki ikili varyantı (hıza rağmen iyimser değil):

./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''

Tamponlu Python:

python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'

Ve Python arabelleksiz:

python -uSc 'import sys
while 1:
 line = sys.stdin.readline()
 if not line: break
 print "[TEST]",line,'

awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'bir zaman damgası
Tino,


3

Stdout ve stderr'ı kullanan bir çözüm istedim, bu yüzden yazıp prepend.shyoluma koydum:

#!/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)

Artık prepend.sh "[ERROR]" cmd ..."[ERROR]" ifadesini çıktıya hazırlamak için koşabilirim cmd, ve hala stderr ve stdout'u ayrı tuttum.


Bu yaklaşımı denedim ama bu >(deniz kabukları üzerinde tam olarak çözemediğim bir şey oldu. Senaryo tamamlanmış gibi gözüküyordu ve komut istemi geri döndükten sonra terminale geliyordu ki bu biraz karışıktı. Sonunda burada cevap geldi stackoverflow.com/a/25948606/409638
robert
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.