views:

75

answers:

4

I have data file that stores records like this:

make=honda|model=civic|color=red
make=toyota|model=corolla|color=blue

What would be the best way to detect (based on the make field) whether a given make exists in the file and then replace it with a new record? (Using shell script)

+2  A: 

For your purposes, the best solution is probably either the stream editor or awk.

Jonathan Feinberg
I know already how to detect the record (awk). But is there a good way of replacing it? Can I use SED somehow to do that?
goe
If only there were some way to turn the words "the stream editor" into some sort of magical portal to the documentation for itself...
Jonathan Feinberg
A: 

This should do it in bash.

#get the file and create an array separated by new lines
lines=$(cat $filename)
IFS=$'\n'
lines=( $lines )
unset IFS


for line in ${lines[@]}
do
    #Get the value of make from the current line
    make=$(echo "$line" | cut -d "|" -f1 | cut -d "=" -f2)

    if [[ "$make" == "$makeImLookingFor" ]]
    then
        echo "modified line"
    else
        echo "$line"
    fi
done
Andrew Myers
+2  A: 

Here is a script that uses a sed command that will do it:

filename='cars'
make='toyota'
replacement='make=nissan|model=sentra|color=green'
sed "s/^make=$make.*/$replacement/" $filename

There are a couple of problems with icarus127's answer which I have fixed and addressed here:

filename='cars'
saveIFS="$IFS"
IFS=$'\n'
# no need to call external cat, make the array at the same time the file is read
lines=($(<$filename))
# IMO, it's better and makes a difference to save and restore IFS instead of unsetting it
IFS="$saveIFS"

make='toyota'
replacement='make=nissan|model=sentra|color=green'

# the array variable MUST be quoted here or it won't work correctly
for line in "${lines[@]}"
do
    # you can use Bash's regex matching to avoid repeatedly calling
    # multiple external programs in a loop
    if [[ $line =~ ^make=$make ]]
    then
        echo "$replacement"
    else
        echo "$line"
    fi    
done

However, that (and the cat version) reads the whole file into an array, which could be a problem if it's large. It's better to use read in a while loop with a redirect:

filename='cars'

make='toyota'
replacement='make=nissan|model=sentra|color=green'

while read -r line
do
    # you can use Bash's regex matching to avoid repeatedly calling
    # multiple external programs in a loop
    if [[ $line =~ ^make=$make ]]
    then
        echo "$replacement"
    else
        echo "$line"
    fi    
done < "$filename"
Dennis Williamson
+1 For improving my script. I'm at best a novice and it's great to see better ways of doing things. Thanks :)
Andrew Myers
A: 

by sed this is is a way

contents of temp.txt make=honda|model=civic|color=red make=toyota|model=corolla|color=blue

new_rec="make=honda|model=civic|color=blue"

$ sed -e "s/^make=honda.*/$new_rec/g" temp.txt make=honda|model=civic|color=blue make=toyota|model=corolla|color=blue

hope this helps

Venkataramesh Kommoju