19

Input:

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

Desired output:

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

How can I add a 0 if there is only a single digit, e.g. 1 in the "day" part? I need this date format: YYYYMM DD.

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
  • Can you explain how this works? This is the first time I'm looking at the \<[0-9]\> construct which I think is the one responsible for matching the single digits but not sure what this construct is called. Thanks. – sasuke Mar 12 '11 at 13:16
  • 2
    \< means: start of a 'word' ... [0-9] means a single digit from 0 to 9 ... \> means: end of a 'word' ... word: a token which is whitespace delimited (or begins/ends at start/end of the line, for \< and \> respectively)... PS. I just tried punctuation marks.. they are also delimiters. – Peter.O Mar 12 '11 at 13:46
  • 1
    You can also do this without capturing parentheses: & in the replacement string will use the matched LHS -- sed 's/\<[0-9]\>/0&/' – glenn jackman Mar 12 '11 at 14:33
  • Oh, wasn't aware that <> is a word boundary in shell regex syntax. Come to think of it, even `sed 's/\b[0-9]\b/0&/' also works. Thank you both. :) – sasuke Mar 12 '11 at 15:18
  • @sasuke: <> is a feature of extended regex (not of the shell, as such)... depending on which version and which options you use, sed and the shell can both use either extended or standard regex ... standard regex uses \<\> – Peter.O Mar 12 '11 at 17:19
18

Another solution: awk '{$2 = sprintf("%02d", $2); print}'

  • +1: This is the most correct solution here even though it does use awk instead of sed – D.Shawley Mar 12 '11 at 19:11
  • Actually, this doesn't work. You need to use awk '{$2=sprintf("%02d", $2)}; printf}' or better yet awk '{$2=sprintf("%02d", $2)}1' to save those poor little keystrokes – SiegeX Mar 12 '11 at 19:18
  • to be more clear, your answer doesn't work as stated because the 'zero-pad' flag only works with the %d format specifier, not %s – SiegeX Mar 12 '11 at 23:11
  • oops right. fixed – glenn jackman Mar 13 '11 at 13:51
  • Not the answer as provided, but it is indeed useful for my problem that led me to this Question in my search. Thanks! – Jesse Steele Jul 16 at 9:54
2

Here is a (non-sed) way to use bash with extended regex..
This method, allows scope to do more complex processing of individual lines. (ie. more than just regex substitutions)

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

output:

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
1

I would do something like this:

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

This grabs lonely numbers, strips them of whitespace with a group ' ([0-9]) ', then places them back in with 0 and whitespace padding ' 0\1 '.

The -E option allows for modern RegEx expressions on OSX (so you don't have to use "\" so often), -r does the same thing on the linux systems I've tested.

-1
while read a b c
do 
new_format=$(printf "%02d" $b)
echo "$a $new_format $c"
done </tmp/input

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.