awk sed if statement


9

Próbuję dodać 0 na początku, JEŻELI występuje „.” przy drugim znaku tej linii. Nie mogłem połączyć tych dwóch;

awk '{ print substr( $0, 2, 1 ) }' file.txt 

pokazując drugą postać

sed -ie "s/.\{0\}/0/" file.txt

dodając zero na początku.

Powinien być napis „jeśli drugi znak jest kropką”.

przykładowy plik:

1.02.2017 23:40:00
10.02.2017 23:40:00

finał:

01.02.2017 23:40:00
10.02.2017 23:40:00

Odpowiedzi:


12

Możemy użyć albo, sedalbo awkcałkowicie rozwiązać problem.


Z sed:

$ sed 's/^.\./0&/' file.txt

Kiedy &występuje w części zastępującej polecenia podstawienia ( s), zostanie on rozwinięty do części wiersza wejściowego, która odpowiada części wzorcowej polecenia.

Wyrażenie regularne ^.\.oznacza „ dopasuj wszystkie linie rozpoczynające się od ( ^) dowolnego znaku ( .), po którym następuje dosłowna kropka ( \.) ”.

Jeśli linia jest 1.02.2017 23:40:00, wzór będzie pasował i 1.zostanie zastąpiony przez 01.na początku linii.


Z awk:

Opierając się na częściowym awkkodzie w pytaniu ...

Spowoduje to, jak powiedziano, wydrukowanie drugiego znaku każdego wiersza wprowadzania:

$ awk '{ print substr($0, 2, 1) }' file.txt

Możemy użyć faktu, który substr($0, 2, 1)zwraca drugi znak i użyć go jako warunku:

$ awk 'substr($0, 2, 1) == "." { ... }' file.txt

Wchodzi w { ... }to kod $0, który jest poprzedzany, czyli zawartość bieżącego wiersza, z zerem, jeśli powyższy warunek jest prawdziwy:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 }' file.txt

Następnie musimy tylko upewnić się, że wszystkie linie są wydrukowane:

$ awk 'substr($0, 2, 1) == "." { $0 = "0" $0 } { print }' file.txt

Warunek substr($0, 2, 1) == "."można oczywiście zmienić również na wyrażenie regularne (używamy dokładnie tego samego wyrażenia, co w sedrozwiązaniu):

$ awk '/^.\./ { $0 = "0" $0 } { print }' file.txt

Niektórzy ludzie, którzy myślą, że „krótszy jest zawsze lepszy” napisaliby to jako

$ awk '/^.\./ { $0 = "0" $0 } 1' file.txt

(i prawdopodobnie również usunąć większość miejsc: awk '/^.\./{$0="0"$0}1' file.txt)


1
+1 Twój ostatni przykład AWK lub przykład sed są prawidłowymi sposobami na to. Zauważ, dla jasności, że będzie to tylko jedno lub drugie.
— Wstrzymano do odwołania.

Moim zdaniem „poprawne” podejście (co nie skrzypce ze spacjami i które jest lżejsze i tak) to ostateczna wersja sed 's/^.\./0&/' file.txt. Myślę, że powinieneś to umieścić na początku tej odpowiedzi. Nadal +1.
— Wildcard

1
@Wildcard Naszym celem jest zadowolenie.
— Kusalananda

5

Z sed:

sed -e "/^.\./s/^/0/" file.txt 

Wzorzec /^.\./szuka dowolnego znaku i dosłownej kropki na początku linii ^, a jeśli to pasuje, należy szamienić ten początek linii na zero, skutecznie dodając zero na początku.

Ekspreso sed s/.\{0\}/0/jest nieco dziwne, dopasowuje zero lub więcej kopii czegokolwiek i zastępuje zero. Wzorzec będzie oczywiście pasował do każdej pozycji ciągu, ale ponieważ s///zastępuje tylko pierwsze dopasowanie, działa zgodnie z przeznaczeniem. Jednak to ciekawy sposób.


Lub z awk, podobne wyrażenie regularne działałoby, aby dopasować linię, ale możemy użyć substr:

awk 'substr($0, 2, 1) == "." {$0 = "0" $0} 1' file.txt 

Najpierw sprawdzamy, czy drugi znak jest kropką, a następnie dodajemy zero na początku linii, jeśli tak jest. Ostatni wywołuje domyślną akcję drukowania linii po jakichkolwiek modyfikacjach.


4

Powiedziałeś awk i sed, ale wygląda na to, że próbujesz sformatować datę i do tego użyłbym datepolecenia. Na przykład:

echo '1.2.2017 23:40:00' | sed 's/\./\//g' | xargs -0 date '+%m.%d.%Y %T' -d

wyjdzie

01.02.2017 23:40:00

sedKomenda w środku zmienia okresów, ukośniki dla wejścia do date -d. Opcje formatu pozwalają na wydruk w prawie dowolnym formacie. W %mszczególności wyzeruje miesiąc, co wydaje się, że próbujesz to zrobić.

Jak zauważa Kusalananda:

Jeszcze bardziej kompaktowy (data GNU i Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'


2
Dobry chwyt! Jeszcze bardziej kompaktowy (data GNU i Bash):date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'
— Kusalananda

Ilekroć mam ukośniki w moich wzorów, ale nie Rury s|\.|/|g. W przeciwnym razie, jak wspomniano powyżej:
— niezły

2

Inna strategia niż przedstawiona w innych odpowiedziach: możesz użyć „.” jako separator pól.

awk -F. '$1 < 10 {printf "0"} {print}' /tmp/in.txt

Możesz zagrać w golfa, aby:

awk -F. '$1<10{printf "0"}1' /tmp/in.txt

W przypadku sed istnieje krótsze polecenie, przedstawione w innej (świetnej) odpowiedzi.


1
Alternatywnie: awk -F. '{print ($1<10?0$0:$0)}' file
— George Vasiliou,

1

Z sed może to być

sed 's/^\(.\)\.\(.*\)/0\1.\2/'

Spowoduje to ^zakotwiczenie na początku linii, a następnie przechwycenie dowolnego pojedynczego znaku w grupie, a następnie literału ., a następnie wszystkiego innego. Jeśli dopasujemy, że wydrukujemy a 0, to nasza pierwsza grupa przechwytywania (znak na początku linii), a .następnie nasza druga grupa przechwytywania (reszta linii)


Przechwytywanie wcale nie jest konieczne. &jest twoim przyjacielem. Zobacz przykład Kusalanandy.
— Wstrzymano do odwołania.

@DennisWilliamson nie jest konieczne, ale biorąc pod uwagę, że istnieją już inne przykłady, pokazuje to inną funkcję, sedktóra może być przydatna w innych sytuacjach, nie tylko ten konkretny problem
— Eric Renouf
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.