Mam plik dziennika, który należy przeanalizować i przeanalizować. Plik zawiera coś podobnego jak poniżej:
Plik:
20141101 server contain dump
20141101 server contain nothing
{uekdmsam ikdas
jwdjamc ksadkek} ssfjddkc * kdlsdl
sddsfd jfkdfk
20141101 server contain dump
W oparciu o powyższy scenariusz muszę sprawdzić, czy wiersz początkowy nie zawiera daty ani numeru, który muszę dołączyć do poprzedniego wiersza.
Plik wyjściowy:
20141101 server contain dump
20141101 server contain nothing {uekdmsam ikdas jwdjamc ksadkek} ssfjddkc * kdlsdl sddsfd jfkdfk
20141101 server contain dump
text-processing
sed
awk
William R.
źródło
źródło
-0
jeśli dotyczy rekordów rozdzielanych przez NUL. Użyj,-0777
aby skasować cały plik w pamięci (którego nie musisz tutaj).Może być trochę łatwiejsze
sed
pierwsza część
:1;N;$!b1
zbierz wszystkie linie w pliku podzielone przez\n
1 długą liniędruga część usuń symbol nowej linii, jeśli występuje po symbolu innym niż cyfrowy, z możliwymi odstępami między nim.
Aby uniknąć ograniczenia pamięci (szczególnie w przypadku dużych plików), możesz użyć:
Albo zapomnij o trudnych
sed
skryptach i pamiętaj, że rok zaczyna się od2
źródło
tr '\n' $'\a' | sed $'s/\a\a*\( *[^0-9]\)/\1/g' | tr $'\a' '\n'
siebie.+
jest\{1,\}
.[\n]
też nie jest przenośny.\n\{1,\}
byłby POSIX.: 1;x
jest zdefiniowanie1;x
etykiety w zestawach POSIX. Więc trzeba:sed -e :1 -e 'N;$!b1' -e 's/\n\{1,\}\( *[^0-9]\)/\1/g'
. Należy również pamiętać, że wielesed
implementacji ma niewielkie ograniczenie wielkości przestrzeni wzorcowej (POSIX gwarantuje tylko 10 x LINE_MAX IIRC).Jednym ze sposobów byłoby:
Jednak .that usuwa również ostatnią nową linię. Aby dodać go ponownie, użyj:
Wyjaśnienie
-l
Usunie końcowe znaki nowej linii (a także dodasz do każdejprint
rozmowy, dlatego używamprintf
zamiast. Następnie, jeśli obecne rozpoczyna linia z liczb (/^\d+/
) oraz numer bieżącego wiersza jest większy niż jeden ($.>1
jest to konieczne, aby uniknąć dodając dodatkowy pusta linia na początku), dodaj a\n
na początku linii.printf
Drukuje każdą linię.Alternatywnie możesz zmienić wszystkie
\n
znaki na\0
, a następnie zmienić te,\0
które znajdują się tuż przed ciągiem liczb, aby\n
ponownie:Aby dopasować tylko ciągi 8 cyfr, użyj tego zamiast tego:
źródło
printf
jest format . Użyjprintf "%s", $_
%10000000000s
na przykład z danymi wejściowymi .perl
,echo %.10000000000f | perl -ne printf
sprowadza moją maszynę na kolana.Spróbuj to zrobić za pomocą awk :
Aby go użyć:
źródło
Kolejny najprostszy sposób (niż moja inna odpowiedź) przy użyciu algorytmu awk i terdon :
źródło
END{print ""}
. Alternatywnie:awk -v ORS= 'NR>1 && /^[0-9]{8}/{print "\n"};1;END{print "\n"}'
źródło
Le program en bash:
w formie jednego wiersza:
Rozwiązanie z zachowaniem ukośników odwrotnych (
read -r
) i spacjami wiodącymi (zarazIFS=
powhile
):formularz jednowierszowy:
źródło
n
. Usuwa również białe znaki. Ale możeszmksh
to zrobić:while IFS= read -r L; do [[ $L = [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]* ]] && print; print -nr -- "$L"; done; print
to zadziała
źródło