2

I have a problem similar to this one, but I can't adapt to my case.

Say I have a file with many of these lines:

f  1/1/519 2/2/2 3/3/520
f  287/4/521 1/5/519 3/6/520
f  5/7/522 1/8/523 287/9/524

I want to replace the content between the two slashes (number/anyNumber/number) of each block.

I would like to have the following result:

f  1//519 2//2 3//520
f  287//521 1//519 3//520
f  5//522 1//523 287//524

What is the correct sed (or anything else) command?

Using MacOS.

Blueko
  • 111
  • 3
  • 10

4 Answers4

2
$ sed 's:/[^/]*/://:g' file
f  1//519 2//2 3//520
f  287//521 1//519 3//520
f  5//522 1//523 287//524
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Could you please try following.

awk '{for(i=1;i<=NF;i++){gsub(/\/.*\//,"//",$i)}} 1'   Input_file

Output will be as follows.

f 1//519 2//2 3//520
f 287//521 1//519 3//520
f 5//522 1//523 287//524
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
1

Easy enough making this pattern-based in sed:

sed 's#/[0-9]*/#//#g' input.txt

This matches any stretch of zero or more digits between two slashes, and replaces the whole bundle with two slashes.

In awk, you might do the same thing this way:

awk '{gsub(/\/[0-9]*\//,"//")} 1' input.txt

The gsub() command is documented on the awk man page. The 1 at the end is a shortcut for "print this line". But you might alternately treat the fields as actual fields:

awk '{for (i=2;i<=NF;i++) {split($i,a,"/"); $i=sprintf("%s//%s",a[1],a[3])} } 1' input.txt

This is more technically "right" in that it treats fields as fields, then treats subfields as subfields. But it'll undoubtedly be slower than the other options, and will also rewrite lines with OFS as field separators.

Lastly, you could use bash alone, without awk or sed:

shopt -s extglob
while read; do echo "${REPLY//\/+([0-9])\////}"; done < input.txt

This works in bash version 3 (since you're using macOS). It reads each line of input then uses Parameter Expansion to make the same translation that was done in the first two options. This solution is likely slower than the others. The extglob shell option is used to make more advanced patterns possible.

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • thanks for the explanations. Just wanted to point out that ` awk '{for (i=2;i<=NF;i++) {split($i,a,"/"); $i=sprintf("%s//%s",a[1],a[3])} } 1' input.txt ` works relative to the question, although if the file has other lines with different content, it adds double slashes in other cases as well. – Blueko Jul 22 '19 at 23:42
  • You're welcome. Yep, I would certainly have addressed the possibility of lines not matching the pattern if there had been any in your sample input. – ghoti Jul 23 '19 at 02:06
0

Answer is rather simple: cat file.txt | sed -e 's/\([0-9]\+\/\)[0-9]\+\(\/[0-9]\+\)/\1\2/g' > mod.txt

Putting something in brackets (()) allows you to refer to it later, using that you remember numbers before the first slash plus the slash (first capture group), match number between the slashes, then remember slash and any numbers after the slash (second capture group), then you just replace whole matched string with first and second capture groups, discarding everything else.

Switch g makes sed operate on every matching occurrence.

Gendalph
  • 21
  • 3
  • **Needless use of** `cat` and `|` **as** `sed` **can take a** `file` **as an argument.** E.g., `sed -i 's/regexp/replacement/' file` or `sed 's/regexp/replacement/' file > newfile` – user3439894 Nov 24 '19 at 07:12