Zerowe liczby do 2 cyfr z sed

19

Wejście:

201103 1 /mnt/hdd/PUB/SOMETHING
201102 7 /mnt/hdd/PUB/SOMETH ING
201103 11 /mnt/hdd/PUB/SO METHING
201104 3 /mnt/hdd/PUB/SOMET HING
201106 1 /mnt/hdd/PUB/SOMETHI NG

Pożądane wyjście:

201103 01 /mnt/hdd/PUB/SOMETHING
201102 07 /mnt/hdd/PUB/SOMETH ING
201103 11 /mnt/hdd/PUB/SO METHING
201104 03 /mnt/hdd/PUB/SOMET HING
201106 01 /mnt/hdd/PUB/SOMETHI NG

Jak dodać 0cyfrę, jeśli jest tylko jedna cyfra, np. 1W części „dzień”? Potrzebuję tego formatu daty: RRRRMM DD.

LanceBaynes
źródło

Odpowiedzi:

13
$ sed 's/\<[0-9]\>/0&/' ./infile
201103 01 /mnt/hdd/PUB/SOMETHING
201102 07 /mnt/hdd/PUB/SOMETH ING
201103 11 /mnt/hdd/PUB/SO METHING
201104 03 /mnt/hdd/PUB/SOMET HING
201106 01 /mnt/hdd/PUB/SOMETHI NG
SiegeX
źródło
Czy możesz wyjaśnić, jak to działa? Po raz pierwszy patrzę na \<[0-9]\>konstrukt, który moim zdaniem odpowiada za dopasowanie pojedynczych cyfr, ale nie jestem pewien, jak nazywa się ten konstrukt. Dzięki.
sasuke
2
\ <oznacza: początek „słowa” ... [0-9] oznacza pojedynczą cyfrę od 0 do 9 ... \> oznacza: koniec „słowa” ... słowo: token z białymi znakami (lub zaczyna / kończy się na początku / końcu linii, odpowiednio dla \ <i \>) ... PS. Właśnie próbowałem znaków interpunkcyjnych .. są one również ogranicznikami.
Peter.O
1
Możesz to również zrobić bez przechwytywania nawiasów: &w ciągu zastępującym użyje dopasowanego LHS -sed 's/\<[0-9]\>/0&/'
glenn jackman
Och, nie wiedziałem, że <>jest to granica słowa w składni wyrażenia regularnego powłoki. Pomyśl o tym, nawet `sed 's / \ b [0-9] \ b / 0 & /' również działa. Dziękuję wam obu. :)
sasuke
@sasuke: <>jest funkcją rozszerzonego wyrażenia regularnego (nie powłoki, jako takiej) ... w zależności od wersji i używanych opcji, sedi shelloba mogą używać rozszerzonego lub standardowego wyrażenia regularnego ... standardowe wyrażenia regularne\<\>
Peter. O
18

Inne rozwiązanie: awk '{$2 = sprintf("%02d", $2); print}'

Glenn Jackman
źródło
2

Oto (nie-sed) sposób użycia basha z rozszerzonym wyrażeniem regularnym .
Ta metoda pozwala na bardziej złożone przetwarzanie poszczególnych linii. (tj. więcej niż tylko podstawienia wyrażeń regularnych)

while IFS= read -r line ; do
    if [[ "$line" =~ ^(.+\ )([0-9]\ .+)$ ]]  
    then echo "${BASH_REMATCH[1]}0${BASH_REMATCH[2]}" 
    else echo "$line"
    fi
done <<EOF
201103 1 /mnt/hdd/PUB/SOMETHING
201102 7 /mnt/hdd/PUB/SOMETH ING
201103 11 /mnt/hdd/PUB/SO METHING
201104 3 /mnt/hdd/PUB/SOMET HING
201106 1 /mnt/hdd/PUB/SOMETHI NG
EOF

wynik:

201103 01 /mnt/hdd/PUB/SOMETHING
201102 07 /mnt/hdd/PUB/SOMETH ING
201103 11 /mnt/hdd/PUB/SO METHING
201104 03 /mnt/hdd/PUB/SOMET HING
201106 01 /mnt/hdd/PUB/SOMETHI NG
Peter.O
źródło
1

Zrobiłbym coś takiego:

sed -E 's/ ([0-9]) / 0\1 /' ./input

To pobiera samotne liczby, usuwa je z grupy z białymi spacjami ' ([0-9]) ', a następnie umieszcza je z powrotem z 0 i dopełnianiem białych znaków ' 0\1 '.

Ta -Eopcja pozwala na nowoczesne wyrażenia RegEx na OSX (więc nie musisz "\"tak często używać ), -rrobi to samo na testowanych przeze mnie systemach Linux.

Eric
źródło
-1
while read a b c
do 
new_format=$(printf "%02d" $b)
echo "$a $new_format $c"
done </tmp/input
Mohamed ELKHALIFI
źródło