9

I am trying to add 0 to the beginning, IF there is a "." at the 2nd character of that line. I couldn't combine these two;

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

showing the second character

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

adding a zero to the beginning.

There should be an "if the second character is a dot".

sample file:

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

final:

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

We may use either of sed or awk to completely solve the problem.


With sed:

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

When & occurs in the replacement part of the substitution command (s), it will be expanded to the part of the input line that matches the pattern part of the command.

The regular expression ^.\. means "match all lines that starts with (^) an arbitrary character (.) followed by a literal dot (\.)".

If the line is 1.02.2017 23:40:00, the pattern will match, and 1. would be replaced by 01. at the start of the line.


With awk:

Building on the partial awk code in the question...

This will, as stated, print the second character of each line of input:

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

We can use the fact that substr($0, 2, 1) returns the second character and use that as the condition:

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

What goes into { ... } is code that prepends $0, which is the contents of the current line, with a zero if the preceding condition is true:

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

Then we just need to make sure that all lines are printed:

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

The condition substr($0, 2, 1) == "." may of course be changed into a regular expression too (we use exactly the same expression as we used in the sed solution):

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

Some people who thinks "shorter is always better" would write that as

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

(and probably also remove most spaces: awk '/^.\./{$0="0"$0}1' file.txt)

  • 1
    +1 Your last AWK example or your sed example are the correct ways to do this. Note, for clarity, that it would only be one or the other. – Dennis Williamson Apr 21 '17 at 19:22
  • In my opinion the "correct" approach (which doesn't fiddle with spaces and which is lighter weight anyway) is your final version, sed 's/^.\./0&/' file.txt. I think you should put that at the start of this answer. Still, +1. – Wildcard Apr 21 '17 at 20:44
  • 1
    @Wildcard We aim to please. – Kusalananda Apr 21 '17 at 21:15
5

With sed:

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

The pattern /^.\./ looks for any character and a literal dot at the start of line ^, and if that matches, substitute that start of line with a zero, effectively adding the zero to the start.

The sed expressoin s/.\{0\}/0/ is somewhat odd, it matches zero or more copies of anything and replaces with a zero. The pattern will of course match in every position of the string, but since s/// only replaces the first match, it works as you intended. A quaint way to do it, though.


Or with awk, a similar regex would work to match the line, but we can use substr:

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

We first test if the second character is a dot, then add a zero to the front of the line if so. The final one invokes the default action of printing the line after any modifications.

4

You said awk and sed, but it seems like you are trying to format a date and for that I would use the date command. For instance:

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

will output

01.02.2017 23:40:00

The sed command in the middle changes the periods to slashes for input into date -d. The format options allow output in almost any format you want. The %m in particular will zero-pad the month, which is what it seems like you are trying to do.

As Kusalananda points out:

Even more compact (GNU date and Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T'

  • 2
    Nice catch! Even more compact (GNU date and Bash): date -f <(tr '.' '/' <dates.in) '+%m.%d.%Y %T' – Kusalananda Apr 21 '17 at 19:16
  • Whenever I have Slashes in my patterns, but no Pipes: s|\.|/|g. Otherwise, as noted above: Nice catch, +1 – Alex Stragies Apr 22 '17 at 6:52
2

A different strategy than presented in the other answers: You could use "." as the field separator.

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

You could golf this to:

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

For sed, there is a shorter command, presented in another (great) answer.

  • 1
    Alternative: awk -F. '{print ($1<10?0$0:$0)}' file – George Vasiliou Apr 23 '17 at 10:56
1

With sed it could be

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

This will use ^ to anchor to the beginning of the line, then capture any single character in a group, followed by a literal ., then anything else. If we match that we print a 0, then our first capture group (the character at the start of the line), then a . then our second capture group (the rest of the line)

  • It's not at all necessary to do any of that capturing. & is your friend. See Kusalananda's sed example. – Dennis Williamson Apr 21 '17 at 19:24
  • @DennisWilliamson not necessary, but given there are other examples already this shows another feature of sed that could be useful in other situations, not just this specific problem – Eric Renouf Apr 22 '17 at 12:31

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.