1

I would like to replace or append in a configuration file like sshd_config:

Key1 value
#Key2 value

The idea of the command is:

$ cmd Key1 home file
$ cmd Key2 house file
$ cmd Key3 flat file

So the resulting file is:

Key1 home
Key2 house
Key3 flat

Any help is more than welcome.

I have taken this as an example but the one that comments and uncomments is not properly working.

Besides I have managed with other options but only for comments or uncommented lines and I want everything in one command if possible.

sed '/^Key\s/{h;s/\(\s\).*/\1newvalue/};${x;/^$/{s//Key newvalue/;H};x}' file

This one gets if the Key exists but, how do I append if it doesn't=

sed -i 's/^#\(Key\s\).*/\1newvalue/g' file

Thanks a lot. I have tried to understand sed but it is quite complex the different spaces and I don't know how to get with # or without.

Edit: Stdout output with -i inplace

$ sudo tee -a /usr/local/bin/conf-space-replace-or-append > /dev/null << 'EOL' 
#!/bin/bash

awk -i inplace -v key="$1" -v val="$2" '
($1 == key) || ($1 == "#"key) { $0 = key OFS val; done=1 }
{ print }
END { if (!done) print key, val }
' "$3" > /dev/null
EOL

$ sudo chmod +x /usr/local/bin/conf-space-replace-or-append
$ sudo conf-space-replace-or-append Port 22 /etc/ssh/sshd_config
jlanza
  • 1,208
  • 3
  • 23
  • 43

1 Answers1

1

sed is for doing s/old/new on an individual line, that is all. For anything else you should be using awk for clarity, simplicity, portability, efficiency, etc., etc.

Just put the following in a file named cmd and execute it as you show in your question.

awk -v key="$1" -v val="$2" '
($1 == key) || ($1 == "#"key) { next }
{ print }
END { print key, val }
' "$3"

The above will delete the existing key+val if present and always appends the new pair to the end of the file. If you'd rather keep an existing key in it's original position in the file and only add new key+val pairs to the end then that's just a tweak:

awk -v key="$1" -v val="$2" '
($1 == key) || ($1 == "#"key) { $0 = key OFS val; done=1 }
{ print }
END { if (!done) print key, val }
' "$3"
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • ok but it prints to stdout. Is this the default behaviour of awk? I know with redirection I can fix it. But even using -i inplace is redirecting to both file and stdout – jlanza Aug 14 '18 at 13:59
  • Yes and `-i inplace` does NOT print to stdout, it only prints to the input file. Remember that `-i inplace` is GNU awk only - maybe you aren't using GNU awk? – Ed Morton Aug 14 '18 at 14:02
  • I guess it is my system is strange because `-i inplace` is both writing to file and stdout. I have included `> /dev/null` redirection ;) – jlanza Aug 14 '18 at 14:14
  • That just can't happen, there's got to be something else going on in your code. Please post the complete contents `cmd` (which must be a minimal script that demonstrates THIS problem) in your question along with the complete sample input and the input file after it runs and the stdout as it's running if you'd like help to debug the problem. – Ed Morton Aug 14 '18 at 15:21
  • There you have... it is just your code ;) Maybe I copied it wrongly ... anyway the /dev/null is not a big deal – jlanza Aug 14 '18 at 15:39
  • I was hoping you'd just `cat` the file that's being executed rather than posting the command you're using to create the file to be executed. idk what the output of that `tee` would look like. Please remove the `> /dev/null` and just post the output of `cat /usr/local/bin/conf-space-replace-or-append` and when you execute it please use the full path to make sure the command you're executing is that file. Also provide the input file before/after the command runs. – Ed Morton Aug 14 '18 at 15:45
  • Hmm, I find it suspicious that you're using `tee -a` to put the awk command into your executable. That will append that awk script to whatever's already present in the file - unless you're removing your executable between calls to `tee` then you're piling up awk commands in your executable every time you run that tee command. I also find it odd that you're using `tee file > /dev/null < file < – Ed Morton Aug 14 '18 at 15:54