2

I have a bash dialog form that generates four variables. Each individual variable - if not empty - will lead to a sed command execution on the same file.

Bash Dialog Script that generates four variables var1, var2, var3, var4

#!/usr/bin/env bash   
response=$(dialog               \
        --title "ini configure"     \
        --form  "Configure php.ini" \
          15 50 0                   \
        "Execution Time:"       1 1    "$exe_time"     1 10 20 0      \
        "Memory Limit:"         2 1    "$mem_limit"    2 10 20 0      \
        "Max File Size:"        3 1    "$max_file"     3 10 20 0      \
        "Max Post Size:"        4 1    "$max_post"     4 10 20 0      \  
        3>&1 1>&2 2>&3 3>&-)
    
    responsearray=($response)
    
    var1=${responsearray[0]} 
    var2=${responsearray[1]} 
    var3=${responsearray[2]} 
    var4=${responsearray[3]}

How to combine these four conditional sed commands?

if [[ -n "$var1" ]]; then   
    sed -i 's/^;*\max_execution_time = .*/max_execution_time = "${var1}"/' /user/php8.0-fpm/php.ini
    
if [[ -n "$var2" ]]; then   
    sed -i 's/^;*\memory_limit = .*/memory_limit = "${var2}"/' /user/php8.0-fpm/php.ini 

if [[ -n "$var3" ]]; then   
    sed -i 's/^;*\max_file_size = .*/max_file_size = "${var3}"/' /user/php8.0-fpm/php.ini
    
if [[ -n "$var4" ]]; then   
    sed -i 's/^;*\max_post_size = .*/max_post_size = "${var4}"/' /user/php8.0-fpm/php.ini

I know I can combine multiple sed commands with a semicolon, but it is the conditional that's creating the issue.

OS: Ubuntu 20.04 Headless

Philippos
  • 13,237
  • 2
  • 37
  • 76
depar
  • 89
  • 1
  • 10

2 Answers2

3

You already accepted the other answer, but if your original idea was to have a single sed command doing the filtering (without the need for shell conditions), you could use a simple trick like:

sed -i "/^${var1}/!s/^;*\(max_execution_time = \).*/\1${var1}/
        /^${var2}/!s/^;*\(memory_limit = \).*/\1${var2}/
        /^${var3}/!s/^;*\(max_file_size = \).*/\1${var3}/
        /^${var4}/!s/^;*\(max_post_size = \).*/\1${var4}/" /user/php8.0-fpm/php.ini

As you see, I added an inverted address to each substitute command. /^${var1}/ will only match, if var1 is empty (or consists of less or equal semicolons than the line has). The ! inverts the match, so the s command is only executed if var carries a value.

Philippos
  • 13,237
  • 2
  • 37
  • 76
  • wow!! that was neat and was new to me - can you add a little bit more explanation as to the inverse match `!` or you can point me to other sources where I can read about it - https://www.grymoire.com/Unix/Sed.html#toc-uh-32 has a little bit about it, but not in details with examples. – depar Sep 30 '21 at 12:40
  • 1
    Most `sed` command can be preceeded by a so-called *address* to filter the lines, where this command should be applied. `3d` will `d`elete only line number 3. `/foo/d` will delete lines that contain `foo`. An `!` invers the match, so `3!d` deletes all lines *except for* line 3; `/bar/!d` deletes all lines that do *not* contain `bar`. Please note that this kind of filtering I used in my answer is not the usage this is intended for, that's why I called it a *trick*. – Philippos Oct 01 '21 at 08:48
2

I'd be inclined to create an array of sed commands, using the -e option to tell sed they're all commands (not one command and some filenames). Also, variable don't expand in single-quotes, so use double-quotes instead. (Note: I assume the double-quotes in the replacement strings were supposed to fix this, but they don't. If the double-quotes are actually supposed to be added to the file, use \" instead.)

So something like this:

sedCommands=()
if [[ -n "$var1" ]]; then   
    sedCommands+=(-e "s/^;*\max_execution_time = .*/max_execution_time = ${var1}/")
fi
    
if [[ -n "$var2" ]]; then   
    sedCommands+=(-e "s/^;*\memory_limit = .*/memory_limit = ${var2}/")
fi

if [[ -n "$var3" ]]; then   
    sedCommands+=(-e "s/^;*\max_file_size = .*/max_file_size = ${var3}/")
fi
    
if [[ -n "$var4" ]]; then   
    sedCommands+=(-e "s/^;*\max_post_size = .*/max_post_size = ${var4}/")
fi

if [[ ${#sedCommands[@]} -gt 0 ]]; then
    sed -i "${sedCommands[@]}" /user/php8.0-fpm/php.ini
else
    echo "No changes made." >&2
fi
Gordon Davisson
  • 4,360
  • 1
  • 18
  • 17
  • I thought double quotes in case of variables `"${var1}"` would expand the variable, so if I understand you - `'"${var1}"'` would have been correct. – depar Sep 30 '21 at 01:49
  • 1
    @depar That won't work, because the shell doesn't recognize nested quotes. In `'"${var1}"'`, the double-quotes are just treated as literally part of the string, not shell syntax that says how to parse their contents. Try `echo '"$HOME"'` and you'll see what I mean. – Gordon Davisson Sep 30 '21 at 01:54
  • @ thnx, got the point, but my point was - `'s/^;*\max_file_size = .*/max_file_size = '"${var1}"'/'` - that would have worked the same way - so just for my knowledge is there any added benefits with `"${var1}"` compared to simply `${var1}` (asking generally, not in the present context) – depar Sep 30 '21 at 02:06
  • 3
    @depar Not double-quoting variable references can cause weird problems in many situations; see [this question](https://unix.stackexchange.com/questions/68694/when-is-double-quoting-necessary/). In this case, it'd mainly cause trouble if any of the variables contained whitespace, which probably shouldn't happen... but if it did, the script would fail in bizarre ways. Anyway, it's generally better to have double-quotes around variable references than to try to think through what might go wrong without them. – Gordon Davisson Sep 30 '21 at 02:11