How can I automate modifying key/value pairs in a shell script?

6,262

I'd use awk for this task:

   awk -F'=' -v "keyname=$SOMEKEY" -v "value=$SOMEOTHERVALUE" '
            $1 == keyname {
                    if ($2 != value) $2 = "\"" value "\""
                    key_found = 1
            }

            { print $1 "=" $2 }

            END { if (!key_found) print keyname "=\"" value "\"" }
   ' fname

assuming

 SOMEKEY=key1
 SOMEOTHERVALUE="John Doe is dead!"

and given this input:

 key1="John Doe is geat!
 key2="Who's John Wayne?"

One gets:

 key1="John Doe is dead!"
 key2="Who's John Wayne?"

Or if no key1 line is present, key1="John Doe is dead!" will be appended at the end.

Note: On Solaris or other UNIX derivates that still ship an old version of awk(1), nawk(1) should be used instead.

Share:
6,262

Related videos on Youtube

wim
Author by

wim

Hi from Chicago! Python dev with interest in mathematics, music, robotics and computer vision. I hope my Q&A have been helpful for you. If one of my answers has saved your butt today and you would like a way to say thank you, then feel free to buy me a coffee! :-D [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo *Click*

Updated on September 18, 2022

Comments

  • wim
    wim over 1 year

    I often want to automate this sort of task in a shell script:

    if the line:

    SOMEKEY=SOMEVALUE

    exists in a file, then change it to

    SOMEKEY=SOMEOTHERVALUE

    otherwise, append the line SOMEKEY=SOMEOTHERVALUE in the file.

    How could I go about this? I think I could do it using a combination of grep and sed, but I'm sure it's a common enough task that someone has already worked out an elegant solution.

    By the way, when replacing I would normally do something like this

    sed -i 's/old/new/g' fname

    But it means I have to be very careful when composing my regular expressions, so as not to make a mistake. Is there an easy way to "preview" what changes which would occur from my call to sed without actually stomping on the file?

  • ktf
    ktf over 12 years
    Missed that last question: If you just want to preview your changes, omit the option -i and code: yoursedcommand |grep fname - That will compare the outcome of your command with the original file fname
  • wim
    wim over 12 years
    i tried, for example, sed 's/HISTSIZE/SPAM/g' ~/.bashrc | grep ~/.bashrc but didn't see any output.
  • ktf
    ktf over 12 years
    So sorry - stupid typo (obviously I was thinking about something else...) Correct is: yoursedcmd | diff fname -
  • wim
    wim over 12 years
    yes i thought you might have meant diff, but when i tried that i get diff: missing operand after /home/wim/.bashrc'`
  • ktf
    ktf over 12 years
    Don't forget the second argument to diff: it's only a single minus sign (-) which indicates that the 2nd file for comparison shall be read from stdin