1

I'm trying to automate a build process by replacing .js chunks for particular lines in my main.config.php file. When I run the following code:

declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")

build_path="./build/build"
config_path="./system/Config/main.config.php"
while read -r line;
do
    for js_string in ${js_strings[@]}
    do
        if [[ $line == *$js_string* ]]
        then
            for js_file in "$build_path"/*
            do
                result="${js_file//[^.]}"
                if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
                then
                    sed -i "s/$line/$line$(basename $js_file)\";/g" $config_path
                fi
            done        
        fi
    done
done < "$config_path"

I get this message back, and file has not been updated/edited:

sed: 1: "./system/Config/main.co ...": invalid command code .

I haven't been able to find anything in my searches that pertain to this specific message. Does anyone know what I need to change/try to get the specific lines replaced in my .php file?

Updated script with same message:

declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")

build_path="./build/build"
config_path="./system/Config/main.config.php"

while read -r line;
do
    for js_string in ${js_strings[@]}
    do
        if [[ $line == *$js_string* ]]
        then
            for js_file in "$build_path"/*
            do
                result="${js_file//[^.]}"
                if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
                then
                    filename=$(basename $js_file)
                    newline="${line//$js_string*/$filename\";}"

                    echo $line
                    echo $newline
                    sed -i "s\\$line\\$newline\\g" $config_path
                    echo ""
                fi
            done        
        fi
    done
done < "$config_path"

Example $line:

$config['public_build_header_css_url'] = "http://localhost:8080/build/headerCSS.js";

Example $newline:

$config['public_build_header_css_url'] = "http://localhost:8080/build/headerCSS.7529a73071877d127676.js";

Updated script with changes suggested by @Vercingatorix:

declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")

build_path="./build/build"
config_path="./system/Config/main.config.php"

while read -r line;
do
    for js_string in ${js_strings[@]}
    do
        if [[ $line == *$js_string* ]]
        then
            for js_file in "$build_path"/*
            do
                result="${js_file//[^.]}"
                if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
                then
                    filename=$(basename $js_file)
                    newline="${line//$js_string*/$filename\";}"

                    echo $line
                    echo $newline
                    linenum=$(grep -n "^${line}\$" ${config_path} | cut -d':' -f 1 )
                    echo $linenum
                    [[ -n "${linenum}" ]] && sed -i "${linenum}a\\
${newline}
                    ;${linenum}d" ${config_path}
                    echo ""

                fi
            done        
        fi
    done
done < "$config_path"
Kevin G
  • 168
  • 2
  • 15
  • before the `while` add `set -xv` (enable debug mode), run your script, review the (debug) output to see what the `sed` command looks like with variables expanded; I'm guessing a variable contains a file path (including forward slashes) which is going to clash with your use of forward slashes as `sed` script delimiters – markp-fuso Nov 12 '21 at 16:51
  • 2
    Please read the description of the tags you applied. Also, create a [mcve]. In particular, I'm wondering if this has anything to do with PHP at all, other than that it's applied to a PHP file. Further, `sed` is a program, not a command built into or specific to Bash. – Ulrich Eckhardt Nov 12 '21 at 16:51
  • adding to Ulrich's comment ... seeing how `sed` is generating the error message ... perhaps add `sed` as a tag? – markp-fuso Nov 12 '21 at 16:53
  • What platform is this running on (and therefore which version of `sed` is this)? Different versions of `sed` have [confusingly different syntax for the `-i` option](https://stackoverflow.com/questions/5694228/sed-in-place-flag-that-works-both-on-mac-bsd-and-linux). Also, there are several variable references that should be double-quoted ([shellcheck.net](https://www.shellcheck.net/) will point most of them out), do those strings in the `sed` command [need to be escaped](https://stackoverflow.com/questions/29613304), and are you sure `./` refers to the directory you expect? – Gordon Davisson Nov 12 '21 at 18:12
  • 1
    You're using `/` as the delimiter for sed's `s` command, but the variable contents contain slashes. Use a different delimiter for `s`. – glenn jackman Nov 12 '21 at 18:53
  • What would be an alternative delimiter? – Kevin G Nov 12 '21 at 20:49
  • Updated my script, but still receiving same message. I'm running on macOS. – Kevin G Nov 12 '21 at 21:05

1 Answers1

1

Using sed's s command to replace a line of that complexity is a losing proposition, because whatever delimiter you choose may appear in the line and mess things up. If these are in fact entire lines, it is better to delete them and insert a new one:

                linenum=$(fgrep -nx -f "${line}" "${config_path}" | awk -F : "{print \$1}" )
                [[ -n "${linenum}" ]] && sed -i "" "${linenum}a\\
${newline}
;${linenum}d" "${config_path}"

What this does is search for the line number of the line that matches $line in its entirety, then extracts the line number portion. fgrep is necessary otherwise the symbols in your file are interpreted as regular expressions. If there was a match, then it runs sed, appending the new line (a) and deleting the old one (d).

Vercingatorix
  • 1,838
  • 1
  • 13
  • 22
  • I added this to my code (see my updated code above), and although I am not getting an "invalid command code", it does not update the lines in my `.php` file. – Kevin G Nov 12 '21 at 22:48
  • I try `echo $linenum` and nothing is outputted to the terminal. – Kevin G Nov 12 '21 at 22:50
  • Do you mean you echoed it in the script immediately after the `grep` execution? That would mean the input line is not exactly matching any line in the config file. Is this expected? – Vercingatorix Nov 12 '21 at 22:57
  • Also, your `${newline}` line needs to be completely flush left (no spaces before it, unindented) or the spaces will appear in your output. – Vercingatorix Nov 12 '21 at 22:58
  • Yes, I ran `echo $linenum` on the line directly below it being defined and nothing is printed, and yes, there will always be matching lines that meet the `js_string` creteria in the `.php` file. – Kevin G Nov 12 '21 at 23:04
  • Updated above what you've suggested, and still no updates to the file, nor anything printed in the terminal. – Kevin G Nov 12 '21 at 23:06
  • Instead of `cut -d':' -f 1` try `awk -F : "{print \$1}"` (updating my answer shortly) – Vercingatorix Nov 12 '21 at 23:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239174/discussion-between-kevin-g-and-vercingatorix). – Kevin G Nov 12 '21 at 23:09
  • Made the change and still the same outcome. – Kevin G Nov 12 '21 at 23:12