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

2 Answers 2

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.

2
  • 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 - grymoire.com/Unix/Sed.html#toc-uh-32 has a little bit about it, but not in details with examples.
    – depar
    Commented Sep 30, 2021 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 delete 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
    Commented Oct 1, 2021 at 8: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
4
  • I thought double quotes in case of variables "${var1}" would expand the variable, so if I understand you - '"${var1}"' would have been correct.
    – depar
    Commented Sep 30, 2021 at 1: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. Commented Sep 30, 2021 at 1: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
    Commented Sep 30, 2021 at 2:06
  • 3
    @depar Not double-quoting variable references can cause weird problems in many situations; see this question. 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. Commented Sep 30, 2021 at 2:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .