Időbélyeg előkészítése a parancs minden kimeneti sorához

Időbélyegzőt szeretnék megadni a parancs minden egyes kimeneti sorához. Például:

foo bar baz 

[2011-12-13 12:20:38] foo [2011-12-13 12:21:32] bar [2011-12-13 12:22:20] baz 

… ahol egyelőre előtag a vonal kinyomtatásának ideje. Hogyan érhetem el ezt?

Megjegyzések

Válasz

moreutils a ts elemet tartalmazza, amely ezt nagyon szépen megcsinálja:

command | ts "[%Y-%m-%d %H:%M:%S]"

Ez megszűnik a hurok szükségessége is, minden kimeneti sorra időbélyeg kerül.

$ echo -e "foo\nbar\nbaz" | ts "[%Y-%m-%d %H:%M:%S]" [2011-12-13 22:07:03] foo [2011-12-13 22:07:03] bar [2011-12-13 22:07:03] baz 

Szeretné tudni, hogy az adott szerver mikor készült újra, amikor újraindította? Csak futtassa ping | ts, a probléma megoldódott: D.

Megjegyzések

  • Honnan nem tudtam erről ?!?!?! Ez csodálatosan egészíti ki a farokot! tail -f /tmp/script.results.txt | ts
  • ha nincs ‘ nincs ts parancsom, mit kell használnom?
  • Ha ‘ nem működik, próbálkozzon a stderr átirányításával stdout-ra pl. ssh -v 127.0.0.1 2>&1 | ts
  • Telepítés a következővel: sudo apt install moreutils a Debianon és yum install moreutils Fedora.
  • Úgy gondolom, hogy a -s paraméter rámutatása hasznos. Amint ez a parancs futási idejét mutatja. Én személy szerint szeretek egyszerre használni a ts és a ts -s. Valahogy így néz ki: command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'. Ez a naplósorokat így készíti elő: [2018-12-04 08:31:00 (00:26:28.267126)] Hai <3

Válasz

Először is, ha arra számít, hogy ezek az időbélyegek valóban egy eseményt képviselnek, ne feledje, hogy mivel sok program soros pufferelést hajt végre (némelyik agresszívebben, mint más), fontos, hogy ezt olyan közelre gondoljuk, mint az eredeti vonal nyomtatásra kerültek, nem pedig egy folyamatban lévő művelet időbélyegzőjére.

Érdemes ellenőrizni, hogy a parancsnak még nincs-e beépített funkciója ennek a feladatnak. Például: ping -D létezik néhány ping verzióban, és az egyes sorok előtt kinyomtatja a Unix-korszak óta eltelt időt. Ha a parancs nem tartalmazza a saját módszerét, néhány módszer és eszköz, amelyek alkalmazhatók, többek között:

POSIX shell

Ne feledje, hogy mivel sok héj belsőleg tárolja húrjait stringként, ha az input tartalmazza a null értéket char acter (\0), ez a sor idő előtti befejezését okozhatja.

command | while IFS= read -r line; do printf "[%s] %s\n" "$(date "+%Y-%m-%d %H:%M:%S")" "$line"; done 

GNU awk

command | gawk "{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0 }" 

Perl

command | perl -pe "use POSIX strftime; print strftime "[%Y-%m-%d %H:%M:%S] ", localtime" 

Python

command | python -c "import sys,time;sys.stdout.write("".join(( " ".join((time.strftime("[%Y-%m-%d %H:%M:%S]", time.localtime()), line)) for line in sys.stdin )))" 

Rubin

command | ruby -pe "print Time.now.strftime("[%Y-%m-%d %H:%M:%S] ")" 

Megjegyzések

  • Az egyik probléma az, hogy sok program bekapcsol még nagyobb kimeneti pufferelés, ha az állomásuk egy cső a terminál helyett.
  • @cjm – Igaz. Bizonyos kimeneti pufferelés enyhíthető a stdbuf -o 0 használatával, de ha a program manuálisan kezeli a kimeneti pufferelését, akkor ‘ nem segít (hacsak nem van lehetőség a kimeneti puffer méretének letiltására / csökkentésére).
  • Python esetén letilthatja a soros pufferelést a python -u
  • @Bwmat No. ... for x in sys.stdin sorokon át ismétlik, anélkül, hogy előbb az összeset a memóriába pufferolná.
  • Tegye ezt, és pufferolást kap … a 1 az 1-ben 1 1 1; aludj 1; visszhang; kész | python -c ‘ sys, time; sys.stdout.write importálás (” ” .join ((” ” .join ((time.strftime (” [% Y-% m-% d% H:% M:% S] “, time.gmtime ()), sor)) a sys.stdin sorhoz))) ‘

Válasz

Soronkénti delta méréshez , próbálkozzon gnomon .

Ez egy parancssori segédprogram, kicsit olyan, mint a moreutils “s ts, hogy az időbélyegző információkat hozzá lehessen rendelni egy másik parancs szabványos kimenetéhez. Hasznos olyan régóta futó folyamatokhoz, ahol olyan történelmi rekordokat szeretnél, amelyek oly sokáig tartanak.

Bármi átírása a gnomonra jelöljön meg minden bélyegzőt egy időbélyegzővel, jelezve, hogy ez a sor mennyi ideig volt az utolsó sor a pufferben – vagyis mennyi ideig tartott a következő sor megjelenése. Alapértelmezés szerint a gnomon megjeleníti az eltelt másodperceket minden sor között, de ez konfigurálható.

gnomon bemutató

Megjegyzések

  • Remek alternatívának tűnik a ts -nek az élő folyamatok használata során. Míg a ts jobban megfelel nem interaktív folyamatoknak.

Válasz

Legszívesebben a fenti megjegyzést tettem volna, de nem tudom, jó hírnévvel. Mindenesetre a fenti Perl-minta az alábbiak szerint törlendő:

command | perl -pe "use POSIX strftime; $|=1; select((select(STDERR), $| = 1)[0]); print strftime "[%Y-%m-%d %H:%M:%S] ", localtime" 

az első “$ |” nem törli a STDOUT-ot. A második a stderr-t állítja be az aktuális alapértelmezett kimeneti csatornaként, és visszavonja azt. Mivel a select visszaadja az eredeti $ | értéket, a selectet egy select-be csomagolva visszaállítjuk a $ | STDOUT.

És igen, kivághatja a “n” beillesztést. Az olvashatóság érdekében sorba állítottam.

És ha valóban pontos akar lenni (és Time :: Hires telepítve van):

command | perl -pe "use POSIX strftime; use Time::HiRes gettimeofday; $|=1; select((select(STDERR), $| = 1)[0]); ($s,$ms)=gettimeofday(); $ms=substr(q(000000) . $ms,-6); print strftime "[%Y-%m-%d %H:%M:%S.$ms]", localtime($s)" 

Megjegyzések

  • Varázslatként működik, nem szabványos csomagok telepítése nélkül.

Válasz

Ryan bejegyzése érdekes ötletet ad, azonban több szempontból kudarcot vall. Miközben teszteltem a tail -f /var/log/syslog | xargs -L 1 echo $(date +"[%Y-%m-%d %H:%M:%S]") $1 t, észrevettem, hogy az időbélyeg ugyanaz marad, ha stdout később jön, másodpercek közötti különbséggel. Tekintsük ezt a kimenetet:

[2016-07-14 01:44:25] Jul 14 01:44:32 eagle dhclient[16091]: DHCPREQUEST of 192.168.0.78 on wlan7 to 255.255.255.255 port 67 (xid=0x411b8c21) [2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: Joining mDNS multicast group on interface wlan7.IPv6 with address fe80::d253:49ff:fe3d:53fd. [2016-07-14 01:44:25] Jul 14 01:44:34 eagle avahi-daemon[740]: New relevant interface wlan7.IPv6 for mDNS. 

A javasolt megoldásom hasonló, azonban megfelelő időbélyegzést biztosít és valamivel hordozhatóbbat használ printf helyett echo

| xargs -L 1 bash -c "printf "[%s] %s\n" "$(date +%Y-%m-%d\ %H:%M:%S )" "$*" " bash 

Miért bash -c "..." bash? Mivel a -c opció miatt először argumentáljon Az nt hozzárendelésre kerül a $0 fájlhoz, és nem jelenik meg a kimenetben. A (z) -c

megfelelő leírását a shell kézikönyv oldalán találhatja meg. A megoldás tesztelése a tail -f /var/log/syslog és (as valószínűleg kitalálhatnád), hogy leválasztottam és újra csatlakoztam a wifi-mhez, megmutatta a date és a syslog üzenetek

A Bash bármilyen bourne-szerű héjjal helyettesíthető, megtehető ksh vagy dash, legalábbis amelyek -c opcióval rendelkeznek.

Lehetséges problémák:

A megoldáshoz xargs szükséges, amely POSIX-kompatibilis rendszereken érhető el, ezért a legtöbb Unix-szerű rendszerre ki kell terjedni. Nyilvánvalóan nem fog működni, ha a rendszere nem kompatibilis a POSIX-szal, vagy ha nincs GNU findutils

Válasz

A legtöbb válasz a date használatát javasolja, de ez elég lassú . Ha a bash verziója nagyobb, mint 4.2.0, akkor jobb, ha az printf t használja, ez egy bash beépített. Ha támogatnia kell a régi bash verziókat, létrehozhatja a log függvényt a bash verziójától függően:

TIMESTAMP_FORMAT="%Y-%m-%dT%H:%M:%S" # Bash version in numbers like 4003046, where 4 is major version, 003 is minor, 046 is subminor. printf -v BV "%d%03d%03d" ${BASH_VERSINFO[0]} ${BASH_VERSINFO[1]} ${BASH_VERSINFO[2]} if ((BV > 4002000)); then log() { ## Fast (builtin) but sec is min sample for most implementations printf "%(${TIMESTAMP_FORMAT})T %5d %s\n" "-1" $$ "$*" # %b convert escapes, %s print as is } else log() { ## Slow (subshell, date) but support nanoseconds and legacy bash versions echo "$(date +"${TIMESTAMP_FORMAT}") $$ $*" } fi 

Lásd a sebességet különbségek:

user@host:~$time for i in {1..10000}; do printf "%(${TIMESTAMP_FORMAT})T %s\n" "-1" "Some text" >/dev/null; done real 0m0.410s user 0m0.272s sys 0m0.096s user@host:~$time for i in {1..10000}; do echo "$(date +"${TIMESTAMP_FORMAT}") Some text" >/dev/null; done real 0m27.377s user 0m1.404s sys 0m5.432s 

UPD: $(date +"${TIMESTAMP_FORMAT}") helyett jobb használni a vagy akár $(exec -c date +"${TIMESTAMP_FORMAT}") túl gyorsított végrehajtás.

UPD2: bash 5 EPOCHREALTIME változót biztosít a mikroszekundumokhoz részletességgel, ezt a parancsot használhatja (csak kb. 30% -kal lassabb, mint a másodpercek): printf "%(${TIMESTAMP_FORMAT})T.%s %5d %s\n" ${EPOCHREALTIME/./ } $$ "$*"

Hozzászólások

  • Ez a válasz nagyon alulértékelt! Különösen jó bemutatni a relatív teljesítményhatást.
  • Kiváló javaslat, de sajnos a dátum nem ad másodperc alatti felbontást, ami esetemben követelmény
  • A bash 5.0+ verzióval ezt a parancsot használhatja: printf "%(${TIMESTAMP_FORMAT})T.%s %5d %s\n" ${EPOCHREALTIME/./ } $$ "$*"

Válasz

Ezt a és xargs:

... | xargs -L 1 echo `date +"[%Y-%m-%d %H:%M:%S]"` $1 

Magyarázat:

xargs -L 1 utasítja az xargs-t, hogy futtassa a folyamat parancsot minden bemeneti sorhoz, és ez halad az első sorban. A echo `date +"[%Y-%m-%d %H:%M:%S]"` $1 alapvetően visszhangozza a dátumot a végén lévő beviteli argumentummal

Megjegyzések

  • A megoldás közel van, de nem ‘ nem időbélyegzi, ha a kimenet hosszú idővel elválasztott. Ezenkívül ‘ használ backtickeket és haven ‘ t idézett $1. Ez ‘ nem jó stílus. Mindig idézze a változókat. Ezenkívül ‘ a echo szolgáltatást használja, amely nem hordozható. ‘ rendben van, de előfordulhat, hogy egyes rendszereken nem működik megfelelően.
  • Ennek tesztelése után úgy tűnik, hogy ‘ teljesen igazad van … tudsz-e valamilyen módszert a date minden sor átértékelése, vagy nagyjából reménytelen?

Válasz

Szégyentelen dugó valamiért csak a pontos probléma megoldására írtam: ets , Go-ban írva.

bemutató

Nagyon sok használati példát talál a projekt oldalon.

A meglévő válaszokkal és hasonló ajánlatokkal szembeni figyelemre méltó különbség az, hogy a ets -et arra tervezték, hogy futtassa a parancsot helyetted, egy pty-ben (pszeudo tty) – vagyis szimulálva a parancsod natív módon fut egy tty alatt. Ahhoz képest, hogy a parancs kimenetét pl. ts, ez többnyire átláthatóvá teszi az időbélyegzést, és megoldja a csővezeték számos kérdését:

  • Egyes programok agresszív módon pufferolnak, amikor pipába írnak, így Ön nem lát kimenetet, majd egy csomó kimenetet (igen, stdbuf-t is megtehetsz, akár be is csomagolhatod az stdbuf-ot és a ts-t egy álnévbe / függvénybe, de nem lenne jobb, ha a dolgok a dobozon kívül működnének);
  • Egyes programok letiltják a színt és / vagy az interaktivitást, amikor pipára írnak;
  • A kilépés állapota eltűnik, hacsak nem kapcsolja be a pipefail-t; stb.

A parancsok legyen közvetlenül végrehajtva “ed, vagyis egyszerűen meg lehet előzni a ets parancsot a meglévő parancssorhoz, vagy lehetnek shell parancsok (amint azt a fenti gif mutatja). Természetesen, ha kimenetet szeretne küldeni, akkor a ets is megteheti.

ets ugyanazt támogatja időbélyeg-módok, mint moreutils ts: abszolút idő, eltelt idő és növekményes idő mód. Saner alapértelmezéseket használ (pl. Az eltelt / növekményes időbélyegekhez mindig monoton órát használnak), és további támogatást nyújt az egyéni időzónákhoz. “Részletes összehasonlítás itt .

Ismét https://github.com/zmwangx/ets . Pörgessen, jelentse a hibákat stb.

Válasz

Tegye ezt a szkript kezdete közelében

# prepend a timestamp to all output exec &> >( ts "%Y-%m-%d.%H%M.%.S " ) 

Vagy további hitelért kimenjen naplófájlba a következőn keresztül:

script_name=foobar log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 ) echo "note: redirecting output to [${log_file}]" exec &> >( ts "%Y-%m-%d %H:%M:%.S " > ${log_file} ) 

mind a konzolba, mind a naplófájlba történő kimenethez:

script_name=foobar log_file=$( printf "/tmp/${script_name}-%(%Y-%m-%d)T.%(%H%M%S)T.log" -1 ) exec &> >( ts "%Y-%m-%d %H:%M:%.S " | tee ${log_file} ) 

Ennek fő előnye, hogy a naplózást el kell különíteni minden mástól, nem pedig a szkript törzsének megzavarása a tee vagy hasonló parancsokon keresztül minden parancsnál, és nem kell egyedi naplózási funkciókat írni, és ragaszkodni kell a sima régi echo.

A ts program megtalálható a moreutils csomagban, amelynek minden ésszerűen elérhető helyen elérhetőnek kell lennie. ésszerű adminisztrációs rendszer. 🙂

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük