简体   繁体   中英

Bash - Changing configuration file with sed

I've been having some problems with a shell script that changes a configuration file named ".backup.conf".

The configuration file looks like this:

inputdirs=(/etc /etc/apm /usr/local)
outputdir="test_outputdir"
backupmethod="test_outputmethod"
loglocation="test_loglocation"`

My script needs to change one of the configuration file variables, and I've had no trouble with the last 3 variables.

If I wanted to change variable "inputdirs" /etc/ to /etc/perl, what expression should I use?

If I use echo with append, it will only append it to the end of the file.

I've tried using sed in the following format: sed -i 's/${inputdirs[$((izbor-1))]}/$novi/g' .backup.conf where "izbor" is which variable I want to change from inputdirs and "novi" is the new path (eg /etc/perl).

So, with the following configuration file, and with variables $izbor=1 and $novi=/etc/perl I should change the first variable inputdirs=/etc to /etc/perl and the variable inputdirs should finally look like inputdirs=(/etc/perl /etc/apm /usr/local)

Thank you for your help!

You could try this:

enovi="$(printf '%s\n' "$novi" | sed -e 's/[\\&/]/\\&/g')"
izbor1="$(expr "$izbor" - 1)"
sed -rie "s/([(]([^ ]* ){$izbor1})[^ )]*/\\1$enovi/" config.txt

A summary of the commands:

  1. The first line generates a variable $enovi that has the escaped contents of $novi . Basically,the following characters are escaped: & , \\ , and / . So /etc/perl becomes \\/etc\\/perl .
  2. We create a new variable decrementing $izbor .
  3. This is the actual substitute expression. I'll explain it in parts:
    1. First we match the parenthesis character [(] .
    2. We will now search for a sequence of non-spaces followed by a space ( [^ ]* ).
    3. This search (identified by grouping in the inner parenthesis) is repeated $izbor1 times ( {$izbor1} )
    4. The previous expressions are grouped into an outer parenthesis group in order to be captured into an auxiliary variable \\1 .
    5. We now match the word we want to replace. It is formed by a sequence of characters that aren't spaces and isn't a closing parenthesis (this is to handle the case of the last word)
    6. The replacement is formed by the captured value \\1 , followed by our new string.

Hope this helps =)

If you are trying to use $izbor as an index, it will probably want to be a flag to s/// . Assuming your input matches ^inputdirs=( (with no whitespace), you can probably get away with:

sed -i '/^inputdirs=(/{ 
    s/(/(  /; s/)/ )/;   # Insert spaces inside parentheses
    s@ [^ ][^ ]* @ '"$novi@$izbor"'; 
    s/( /(/; s/ )/)/; }  # Remove inserted spaces
' .backup.conf

The first two expressions ensure that you have whitespace inside the parentheses, so may not be necessary if your input already has whitespace there. It's a bit obfuscated above, but basically the replacement you are doing is something like:

s@ [^ ][^ ]* @/etc/perl@2

where the 2 flag tells sed to only replace the second occurrence of the match. This is really fragile, since it requires no whitespace before inputdirs and whitespace inside the parens and does not handle tabs, but it should work for you. Also, some sed allow [^ ][^ ]* to be written more simply as [^ ]+ , but that is not universal.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM