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.