Нулевое заполнение до 2 цифр с помощью sed

19

Входные данные:

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

Желаемый вывод:

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

Как я могу добавить, 0если есть только одна цифра, например, 1в части «день»? Мне нужен этот формат даты: ГГГГММ ДД.

LanceBaynes
источник

Ответы:

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
источник
Можете ли вы объяснить, как это работает? Это первый раз, когда я смотрю на \<[0-9]\>конструкцию, которая, как мне кажется, отвечает за сопоставление однозначных цифр, но не уверена, как называется эта конструкция. Благодарю.
Саске
2
\ <означает: начало слова ... ... [0-9] означает одну цифру от 0 до 9 ... \> означает: конец слова ... слово: токен, разделенный пробелом (или начинается / заканчивается в начале / конце строки, для \ <и \> соответственно) ... PS. Я только что попробовал знаки препинания .. они также являются разделителями.
Peter.O
1
Вы также можете сделать это без захвата скобок: &в строке замены будет использоваться соответствующий LHS -sed 's/\<[0-9]\>/0&/'
glenn jackman
О, не знал, что <>это граница слова в синтаксисе регулярных выражений оболочки. Если подумать, даже `sed 's / \ b [0-9] \ b / 0 & /' также работает. Спасибо вам обоим. :)
Саске
@sasuke: <>это особенность расширенного регулярного выражения (а не оболочки) как такового ... в зависимости от того, какую версию и какие опции вы используете, sedи shellможет использовать как расширенное, так и стандартное регулярное выражение ... стандартное регулярное выражение\<\>
Питер. O
18

Другое решение: awk '{$2 = sprintf("%02d", $2); print}'

Гленн Джекман
источник
2

Вот (не sed) способ использовать bash с расширенным регулярным выражением .
Этот метод позволяет области видимости выполнять более сложную обработку отдельных строк. (т.е. больше, чем просто подстановка регулярных выражений)

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

выход:

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
источник
1

Я бы сделал что-то вроде этого:

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

Это захватывает одинокие числа, удаляет их из пробелов с группой ' ([0-9]) ', затем помещает их обратно с 0 и пробелами ' 0\1 '.

-EОпция позволяет для современных RegEx выражений на OSX (так что вам не придется использовать "\"так часто), -rделает то же самое на Линукс системах я проверил.

Эрик
источник
-1
while read a b c
do 
new_format=$(printf "%02d" $b)
echo "$a $new_format $c"
done </tmp/input
Мохамед ЭЛХАЛИФИ
источник