mdumreth52
mdumreth52

Reputation: 21

SED command not functioning correctly

I have a file test.file which has following lines.

abc01.hostname.com
xyzabc01.hostname.com
xyzabc02.hostname.com

I have script - for sed which should print output as below

[abc]
abc01.hostname.com
[xyzabc]
xyzabc01.hostname.com
xyzabc02.hostname.com

But I'm getting below output.

[abc]
abc01.hostname.com
[abc]
[xyzabc]
xyzabc01.hostname.com
xyzabc02.hostname.com

Don't know why [abc] is getting duplicated. Any suggestions? below is the script which I am using.

#!/bin/bash
for i in `test.file | cut -d. -f1 | sed 's/[0-9]//g' | uniq`
do
    {
        name=$(cat test.file | grep ^$i[0-9] | head -1)
        sed -i "/$name/i \[$i\]" test.file
    }
done

Upvotes: 2

Views: 149

Answers (4)

potong
potong

Reputation: 58568

This might work for you (GNU sed):

sed -E 'G;/^([[:alpha:]]+).*\n\1/{P;d};s/\n.*//;h;s/^([[:alpha:]]+).*/[\1]\n&/' file

This solution works by comparing the current key with the previous. The previous key is stored in the hold space and replaced when the key changes. On a change of key the leading alpha characters are converted into an extra record surrounded by [ and ]. If the key is unchanged, the current record is printed as normal.

Upvotes: 0

William Pursell
William Pursell

Reputation: 212634

I wouldn't use sed for this. Just do:

awk '$1 != last_prefix {print "[" $1 "]"} 1; {last_prefix=$1}' FS=[0-9] test.file

Upvotes: 2

Paul Hodges
Paul Hodges

Reputation: 15418

Let's clean this up a bit.

for i in `cat test.file | cut -d. -f1 | sed 's/[0-9]//g' | uniq`

Don't do this. Don't use a subshell to supply a list to for, don't use cat to feed programs that could read the file directly, don't use a long pipeline when the subprocesses aren't needed...

name=$(cat test.file | grep ^$i[0-9] | head -1)

If you are using bash, there's no nead to run three (technically four?) subprocesses on every iteration to get this edited string. c.f. this page.

#!/bin/bash
last=''
while read name
do label="${name%%[.0-9]*}"
   if [[ "$label" != "$last" ]]
   then echo "[$label]" # or printf "\n$label\n" for a separator line
        last="$label"
   fi
   echo "$name"
done < test.file > file.redux

Output:

[abc]
abc01.hostname.com
[xyzabc]
xyzabc01.hostname.com
xyzabc02.hostname.com

Then if you are satisfied with the results,

mv file.redux test.file

All handled in bash quickly and efficiently with no spawning until and unless the result is good.

If you think it will be a LOT of data, try awk with the same logic. :)

Upvotes: 2

javier_domenech
javier_domenech

Reputation: 6273

You forgot to indicate the start of line also in the sed command:

#!/bin/bash
for i in `cat test.file | cut -d. -f1 | sed 's/[0-9]//g' | uniq`
do
    {
        name=$(cat test.file | grep ^$i[0-9] | head -1)
        sed -i "/^$name/i \[$i\]" test.file
    }
done

Upvotes: 1

Related Questions