Delete whitespace between two specific words in sed - sed

The input is:
"At 12: 30 then"
I have tried this, but it doesn't work:
echo "At 12: 30 then" | sed -e "/[0-9]\+:\(\s\+\)[0-9]\+/d"
The expected output is:
At 12:30 then

Careful there, the delete command in sed is within the context of a line, you probably need to substitute instead.
echo "At 12: 30 then" | sed -e "s/\([0-9]\+\):\(\s\+\)\([0-9]\+\)/\1:\3/"

My proposition:
echo "At 12: 30 then" | sed "s/\([0-9]\+\)\s*:\s*\([0-9]\+\)/\1:\2/"
echo "At 12 : 30 then" | sed "s/\([0-9]\+\)\s*:\s*\([0-9]\+\)/\1:\2/"

The backslash escape forest can be avoided with -E (or also -r for GNU sed):
$ sed -E 's/([0-9]+:) *([0-9]+)/\1\2/' <<< 'At 12: 30 then'
At 12:30 then

Related

combine sed d and sed a scripts to a single script

file xz.txt
123
456
789
I want to merge
sed -i '1d' xz.txt
sed -i '1a abc' xz.txt
I tried
sed -i -e '1d' -e '1a abc' xz.txt
expect to get
456
abc
789
but I got
456
789
sed (GNU sed) 4.7
but it doesn't work, any help?
Sed goes line by line, first command 1d - deleted 1st line, 1st line is gone, there is no more 1st line, that is why second command 1a abc didn't work. Here is how it should be:
$ sed '1d; 2a abc' f
456
abc
789
What is going on is that the delete statement automatically ends the processing sequence:
[1addr]a\
text Write text to standard output as described previously (yes there is a new-line here)
[2addr]d: Delete the pattern space and start the next cycle
Source: Posix)
As the a command does not modify the pattern space but just writes to stdout, you can simply do
[POSIX]$ sed -e '1a\
abc' -e '1d'
[GNU]$ sed -e '1a abc' -e '1d'
However, the easiest is just to use the replace command c:
[POSIX]$ sed -e '1c\
abc'
[GNU]$ sed -e '1c abc`
Note: The reason the commands a and c write directly to the output and not to the pattern space is most likely that it would mess up the address ranging using line-numbers.

Insert line numbers into file with sed

I am learning how to use sed, and saw that I can use the = to insert line numbers. However, this includes a newline:
file:
alpha
beta
gamma
running sed -n '=;p' file:
1
alpha
2
beta
3
gamma
Is it possible, in a single call to sed, to insert these line numbers on the same line? So:
1 alpha
2 beta
3 gamma
I know that it is possible to do this with other tools, but I am wondering about the specific functionality of sed. Is there a way to append perhaps another regular-expression substitution after the = to remove newlines?
This would be work for you.
sed '=' file | sed 'N; s/\n/ /'
Both orders:
echo -e "Jan J.\nKarel K.\nPetr P." |sed -rn "=;p;"| sed -r "N;s/\n/ /;"
1 Jan J.
2 Karel K.
3 Petr P.
echo -e "Jan J.\nKarel K.\nPetr P." |sed -rn "p;=;"| sed -r "N;s/\n/ /;"
Jan J. 1
Karel K. 2
Petr P. 3
echo -e "Jan J.\nKarel K.\nPetr P." |sed -rn "=;p;" | sed -r "N;s/\n/ /;" | sed -r 's/^([0-9]*) (.*) (.*)$/\2 \1 \3/'
Jan 1 J.
Karel 2 K.
Petr 3 P.

How to remove after second period in a string using sed

In my script, have a possible version number: 15.03.2 set to variable $STRING. These numbers always change. I want to strip it down to: 15.03 (or whatever it will be next time).
How do I remove everything after the second . using sed?
Something like:
$(echo "$STRING" | sed "s/\.^$\.//")
(I don't know what ^, $ and others do, but they look related, so I just guessed.)
I think the better tool here is cut
echo '15.03.2' | cut -d . -f -2
This might work for you (GNU sed):
sed 's/\.[^.]*//2g' file
Remove the second or more occurrence of a period followed by zero or non-period character(s).
$ echo '15.03.2' | sed 's/\([^.]*\.[^.]*\)\..*/\1/'
15.03
More generally to skip N periods:
$ echo '15.03.2.3.4.5' | sed -E 's/(([^.]*\.){2}[^.]*)\..*/\1/'
15.03.2
$ echo '15.03.2.3.4.5' | sed -E 's/(([^.]*\.){3}[^.]*)\..*/\1/'
15.03.2.3
$ echo '15.03.2.3.4.5' | sed -E 's/(([^.]*\.){4}[^.]*)\..*/\1/'
15.03.2.3.4

How to replace only last match in a line with sed?

With sed, I can replace the first match in a line using
sed 's/pattern/replacement/'
And all matches using
sed 's/pattern/replacement/g'
How do I replace only the last match, regardless of how many matches there are before it?
Copy pasting from something I've posted elsewhere:
$ # replacing last occurrence
$ # can also use sed -E 's/:([^:]*)$/-\1/'
$ echo 'foo:123:bar:baz' | sed -E 's/(.*):/\1-/'
foo:123:bar-baz
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):/\1-/'
456:foo:123:bar:789-baz
$ echo 'foo and bar and baz land good' | sed -E 's/(.*)and/\1XYZ/'
foo and bar and baz lXYZ good
$ # use word boundaries as necessary - GNU sed
$ echo 'foo and bar and baz land good' | sed -E 's/(.*)\band\b/\1XYZ/'
foo and bar XYZ baz land good
$ # replacing last but one
$ echo 'foo:123:bar:baz' | sed -E 's/(.*):(.*:)/\1-\2/'
foo:123-bar:baz
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):(.*:)/\1-\2/'
456:foo:123:bar-789:baz
$ # replacing last but two
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):((.*:){2})/\1-\2/'
456:foo:123-bar:789:baz
$ # replacing last but three
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):((.*:){3})/\1-\2/'
456:foo-123:bar:789:baz
Further Reading:
Buggy behavior if word boundaries is used inside a group with quanitifiers - for example: echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/' fails
Greedy vs. Reluctant vs. Possessive Quantifiers
Reference - What does this regex mean?
sed manual: Back-references and Subexpressions
This might work for you (GNU sed):
sed 's/\(.*\)pattern/\1replacement/' file
Use greed to swallow up the pattern space and then regexp engine will step back through the line and find the first match i.e. the last match.
A fun way to do this, is to use rev to reverse the characters of each line and write your sed replacement backwards.
rev input_file | sed 's/nrettap/tnemecalper/' | rev

Regex to extract date and time from log

echo "INFO|2016-11-06 18:44:07.577|G|SOME_THING_IN_CAPS|/something/pages1.html" | \
sed -rn "s/(.*\|)([0-9]{4}-[0-9]{2}-[0-9]{2})\ ([0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3})\2\3/p"
Hi Guys,
i am trying to extract the date and time from the line above. Can you tell me what is missing?
I get this error, not sure how to troubleshoot it
sed: -e expression #1, char 81: unterminated `s' command
awk or cut is better suited for this task
$ s='INFO|2016-11-06 18:44:07.577|G|SOME_THING_IN_CAPS|/something/pages1.html'
$ echo "$s" | awk -F\| '{print $2}'
2016-11-06 18:44:07.577
$ echo "$s" | cut -d\| -f2
2016-11-06 18:44:07.577
The is no substitution string in your command. The s command must contain 3 delimiters: s/pattern/string/.
Try this:
$ echo "INFO|2016-11-06 18:44:07.577|G|SOME_THING_IN_CAPS|/something/pages1.html" | sed -rn "s/.*\|([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}).*/\1/p"
2016-11-0618:44:07.577
Moreover, as pointed out in comments:
you just need one capturing group for date and time
dots characters must be escaped in pattern (\.[0-9]{3}, not .[0-9]{3}), but not space characters ({2} [0-9], not {2}\ [0-9]