0

Input strings are as follows.

6.5.1.2.3
6.10.3.9.6
7.2.0.0.0
10.11.12.13.4

And I want to extract first two digit and replace period character to underscore using sed

6_5
6_10
7_2
10_11

When I used this:

sed 's/\./_/g' | cut -c 1-3

6_10, 10_11 result was not correct.

Is there any work around here?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
Steve Park
  • 51
  • 6

4 Answers4

4

awk is also useful for such things. If you set the output field separator OFS:

$ awk -F"." -v OFS="_" '{print $1, $2}' file
6_5
6_10
7_2
10_11

But if you really need sed use back references (here with extended regular expressions — note that the option is sometimes -E and sometimes only basic regular expressions are supported by sed):

$ sed -r 's/([0-9]+)\.([0-9]+).*/\1_\2/' file
6_5
6_10
7_2
10_11

If you want to perform in-place replacing, you can either say awk/sed '...' file > tmp_file && mv tmp_file file or, use sed -i (on those platforms where it is supported, but note that there are differences between GNU sed and BSD (macOS) sed), or gawk -i inplace (GNU Awk).

Note in both cases I am using a single command instead of piping to another one.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
fedorqui
  • 275,237
  • 103
  • 548
  • 598
1

You are almost there:

echo 1.2.3.4 | sed 's/\./_/g' | cut -d "_" -f1,2

(Escaped the dot with \, and specified the delimiter for cut.)

Florin Ghita
  • 17,525
  • 6
  • 57
  • 76
1

The input is so simple it can be done easily with just cut and tr. Use cut to pick out the first two fields (delimited by .), and then use tr to change the dot to an underscore:

$ cut -d '.' -f 1,2 input | tr '.' '_'
6_5
6_10
7_2
10_11
Kusalananda
  • 14,885
  • 3
  • 41
  • 52
  • Why would you use two processes when there is already a simpler, better explained answer using one. – 123 Jul 25 '16 at 08:42
  • @123 I generally try to use tools that are designed to do what I use them for. Both `sed` and `awk` felt a bit too general. This also way faster than `sed` or `awk` (`sed` being the slowest solution by far). – Kusalananda Jul 25 '16 at 08:53
  • @Kusalanda, how have you come to the conclusion that this is faster? Also how are sed and awk not designed to manipulate text? – 123 Jul 25 '16 at 09:02
  • @123 By timing my answer and the suggestions made by @fedorqui on 1000000 lines of input. `awk`: 1.57s, `sed`: 7.74s, `cut`+`tr`: 0.62s – Kusalananda Jul 25 '16 at 09:07
  • awk is quickest on my machine for 2048512 lines,(from catting original together) – 123 Jul 25 '16 at 09:10
  • @123 `sed` is designed to manipulate text, and `awk` in more or less a general programming language. In this case though, the input is so simple that regular expression manipulation with `sed` seems overkill. – Kusalananda Jul 25 '16 at 09:10
  • `awk in more or less a general programming language`, it's really not, it is 100% designed for text processing. – 123 Jul 25 '16 at 09:14
  • @123 I never said it wasn't. What is the real issue that you're getting at here? What's the constructive critique? – Kusalananda Jul 25 '16 at 09:16
  • You just did, I even quoted it?? – 123 Jul 25 '16 at 09:16
  • @123 No, I said what you quoted, which includes simple extraction and manipulation of characters on a line-by-line basis. The Awk language is more general than just using `awk` as a simple stream editor though. That is why I said it's "more or less a general programming language". – Kusalananda Jul 25 '16 at 09:21
0

My awk solution would be :

$ echo "6.5.1.2.3
> 6.10.3.9.6
> 7.2.0.0.0
> 10.11.12.13.4" | awk 'BEGIN{FS=".";OFS="_"}{print $1,$2}'
6_5
6_10
7_2
10_11
Мона_Сах
  • 322
  • 3
  • 12