Mam plik zawierający daty epoki, które muszę przekonwertować na czytelne dla człowieka. Wiem już, jak wykonać konwersję daty, np .:
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
.. ale staram się wymyślić, jak sed
przejść przez plik i przekonwertować wszystkie wpisy. Format pliku wygląda następująco:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
mechanik
źródło
źródło
HISTTIMEFORMAT
zmienną powłoki, aby kontrolować format w czasie pisania.date -d
nie jest przenośny, żeby powiedzieć, że Solaris ... Zakładam, że jest to system z większością narzędzi GNU? (GNU AWK / Perl to zwykle bardziej przenośne metody radzenia sobie z konwersjami dat).gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
wydaje się nieprzenośny ...)Odpowiedzi:
Zakładając spójny format pliku,
bash
możesz odczytać plik linia po linii, sprawdzić, czy jest w danym formacie, a następnie wykonać konwersję:BASH_REMATCH
to tablica, której pierwszym elementem jest pierwsza grupa przechwycona w dopasowaniu Regex=~
, w tym przypadku epoka.Jeśli chcesz zachować strukturę plików:
spowoduje to przesłanie zmodyfikowanej zawartości do STDOUT, aby zapisać ją w pliku np .
out.txt
:Teraz, jeśli chcesz, możesz zastąpić oryginalny plik:
Przykład:
źródło
bash
,printf
może to zrobić sam konwersji:printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Chociaż jest to możliwe w GNU
sed
z takimi rzeczami jak:Byłoby to wyjątkowo nieefektywne (i łatwo wprowadzić luki w zabezpieczeniach polegające na wstrzykiwaniu dowolnych poleceń 1 ), ponieważ oznaczałoby to uruchomienie jednej powłoki i jednego
date
polecenia dla każdej#xxxx
linii, praktycznie tak źle, jakwhile read
pętla powłoki . Lepiej byłoby użyć takich rzeczy jakperl
lubgawk
, to znaczy narzędzi do przetwarzania tekstu, które mają wbudowane funkcje konwersji daty:Lub:
1 Gdybyśmy napisali
^#([0-9]).*
zamiast^#([0-9]).*$
(jak to zrobiłem we wcześniejszej wersji tej odpowiedzi), to w lokalizacjach wielobajtowych, takich jak UTF-8 (obecnie norma), z wejściem typu#1472047795<0x80>;reboot
, gdzie to<0x80>
jest wartość bajtu 0x80, która nie tworzy poprawnego znaku, tos
polecenie skończyłoby siędate -d@1472047795<0x80>; reboot
na przykład uruchomieniem . Chociaż z dodatkowymi$
wierszami te nie zostałyby zastąpione. Alternatywnym podejściem byłoby:,s/^#([0-9])/date -d @\1 #/e
to znaczy pozostawić część po#xxx
dacie jako komentarz powłokiźródło
date -f
do wykonania wszystkich konwersji w sposób strumieniowy?s
flagi powoduje, że.*
zawiera także nowy wiersz na wejściu. Możesz także użyćstrftime "%c", localtime $1
.Wszystkie pozostałe odpowiedzi
date
powodują pojawienie się nowego procesu dla każdej daty epoki, którą należy przekonwertować. Może to potencjalnie zwiększyć obciążenie wydajnościowe, jeśli dane wejściowe są duże.Jednak data GNU ma przydatną
-f
opcję, która pozwala jednemu procesowidate
na ciągłe odczytywanie danych wejściowych bez potrzeby nowego widelca. Możemy więc użyćsed
,paste
idate
w ten sposób, że każdy zostanie spawnowany tylko raz (2x dlased
), niezależnie od tego, jak duże jest wejście:sed
polecenia odpowiednio usuwają parzyste i nieparzyste linie danych wejściowych; pierwszy zastępuje również#
ze@
dać poprawny format epoka datownika.sed
przesyłane jest pierwsze wyjście, dodate -f
którego dokonuje wymaganej konwersji daty, dla każdego otrzymanego wiersza danych wejściowych.paste
. Te<( )
konstrukcje są bash substytucje procesowe , które skutecznie sztuczka wklej do myśli, że czyta z podanych nazwach plików, kiedy jest w rzeczywistości czyta wyjście rurami od wewnątrz polecenia.-d '\n'
każepaste
oddzielić nieparzyste i parzyste linie wyjściowe znakiem nowej linii. Możesz to zmienić (lub usunąć), jeśli na przykład chcesz znacznik czasu w tym samym wierszu, co w innym tekście.Zauważ, że w tym poleceniu jest kilka GNUizmów i Baszizmów. Nie jest to zgodne z Posix i nie należy oczekiwać, że będzie przenośne poza światem GNU / Linux. Na przykład
date -f
robi coś innego w wariancie BSD OSXesdate
.źródło
date -d
(z pytania) jest również nieprzenośny ... (Na FreeBSD będzie próbował zadzierać z ustawieniami DST, w Solarisie da błąd ...) Pytanie nie określa jednak systemu operacyjnego ...Zakładając, że format daty, który masz w swoim poście, jest tym, czego chcesz, następujący regex powinien pasować do twoich potrzeb.
Pamiętaj, że zastąpi to tylko jedną epokę w wierszu.
źródło
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
przy użyciu sed:
wynik :
ponieważ moim językiem regionalnym jest arabski :)
źródło
Moje rozwiązanie, jak to zrobić w potoku
źródło