10

I am new to programming!!

Can anyone help to remove the : at the first position in a timestamp: :29.06.2019 23:03:17

Presently I am trying to do it using awk/cut commands as shown below:

TDS="$(grep 'Logfile started' process.log |  awk '{print $3,$4}' | cut -d: -f2)"
echo "$TDS"


29.06.2019 23

And the output is not what I wanted! I want to print it as 29.06.2019 23:03:17.

6 Answers 6

14

To cut off the first character, you can also use cut -c:

$ echo ":29.06.2019 23:03:17" | cut -c 2-
29.06.2019 23:03:17
0
11

Use

cut -d: -f2-

instead of

cut -d: -f2

to get anything from the second field to the end of line:

TDS="$(grep 'Logfile started' process.log |  awk '{print $3,$4}' | cut -d: -f2-)"
echo "$TDS"
9

awk is a cool tool, and you can solve very complex tasks with it. But for your question I would rather stick to the basic capabilities of bash.

For this easy substing removal, I would do the following:

zehe="Logfile started :29.06.2019 23:03:17"
echo "${zehe#*:}"

this will print:

29.06.2019 23:03:17

When I was in your position and started to learn programming and bash, I learned a lot of this Handbook:

ABS - Advanced Bash-Scripting Guide

Some more examples and interesting information to your problem can be found here, look for 'Substring Removal'.

2
  • 3
    +1 This! Since the question is tagged "bash", it should be considered preferring bash's great (though often quite obscure) capabilities of manipulating strings which are much faster than loading external tools. Jul 17, 2019 at 9:32
  • 2
    @rexkogitans since we're already calling grep or awk to parse a file, bash will not be faster. In fact, whenever you need to parse a file bash will be slow. All shells are slow and bash is slower than most. That said, the shell's string manipulation capabilities are indeed often the best approach, but only if you already have the input as a variable.
    – terdon
    Jul 17, 2019 at 20:31
9

Here is a sed solution:

$ echo ':29.06.2019 23:03:17' | sed 's/^://'
29.06.2019 23:03:17

What the command sed 's/^://' is doing is substitute s the colon character : from the beginning ^ of each line with the empty string //.

Here is a tricky awk solution, where we changing the field separator to ^:, described above, and output the second field (of each line):

$ echo ':29.06.2019 23:03:17' | awk -F'^:' '{print $2}'
29.06.2019 23:03:17

The task could be accomplished also with grep (explanation), probably this could be the fastest solution for large amount of data:

$ echo 'Logfile started :29.06.2019 23:03:17' | grep -Po '^Logfile started :\K.*'
29.06.2019 23:03:17

Or process the file directly by the following command, where the limitation ^ is removed:

grep -Po 'Logfile started :\K.*' process.log

The above could be achieved also by sed and capture groups ()->\1:

sed -nr 's/^.*Logfile started :(.*)$/\1/p' process.log

Where the expression ^.*<something>.*$ will match the whole line, that contains <something>. The command s/old/new/ will substitute this line by the content of the first capture group (the expression in the brackets could be more concrete). The option -r enables the extended regular expressions. The option -n will suppress the normal output of sed and finally the command p will print the matches.

1
  • I never knew awk could have a multi character FS with characters with special meaning! Thing I learnt today.
    – Floris
    Jul 20, 2019 at 7:35
7

Since you're already processing this in awk, you may as well do the whole thing directly:

$ echo "foo bar :29.06.2019 23:03:17" |  awk '{sub(/^:/,"",$3); print $3,$4}' 
29.06.2019 23:03:17

The sub command's general format is sub(/REGEX/, REPLACEMENT, TARGET) and will replace all matches for the regular expression REGEX with the string REPLACEMENT in the input string TARGET. Here, we are replacing the first : (^ means "the beginning") from the 3rd field ($3) with nothing.

Of course, if you're doing that in awk, you may as well do everything in awk and get the whole thing done in a single operation:

$ echo "Logfile started :29.06.2019 23:03:17" | 
    awk '/Logfile started/{sub(/^:/,"",$3); print $3,$4}' 
29.06.2019 23:03:17

Or, in your case:

TDS="$(awk '/Logfile started/{sub(/^:/,"",$3); print $3,$4}' process.log)"
echo "$TDS"
1
  • This is the best answer, because it actually solves the OP, and also explains why using awk alone is better than a pipeline of awk and sed or cut.
    – mike
    Jun 5, 2023 at 2:05
0

Another bash solution:

$ echo "Logfile started :29.06.2019 23:03:17" | xargs bash -c 'echo "${2#*:} $3"'
29.06.2019 23:03:17
  • This uses the pipeline instead of intermediate variable assignment.
  • The command xargs converts stdin (standard input) to positional parameters for bash command.
  • Replace echo with tail -n1 /path/to/reportfile.txt.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .