1

I have a bash script that runs, and I'm trying to use a Perl one-liner to replace some text in a file variables.php

However, I would like to check if the Perl one-liner runs successfully and that's where I get hung up. I could just output the one-liner and it would work fine, but I would like to know for sure that it ran.

Basically, the function replace_variables() is the function that does the update, and it's the if statement there that I would like to check if my one-liner worked properly.

I've tried using the run_command function in that if statement, but that did not work, and I've tried putting the one-liner directly there, which also didn't work.

If I don't wrap it in an if statement, and just call the one-liner directly, everything works as intended.

here's the full file

#!/bin/bash

export CLI_CWD="$PWD"

site_variables() {
  if [ -f "$CLI_CWD/variables.php" ]; then
    return true
  else
    return false
  fi
}

replace_variables() {
  # perl -pi -e 's/(dbuser)(\s+)=\s.*;$/\1 = Config::get("db")["user"];/; s/(dbpass)(\s+)=\s.*;$/\1 = Config::get("db")["pass"];/; s/(dbname)(\s+)=\s.*;$/\1 = Config::get("db")["database"];/' "$CLI_CWD/variables.php"
  if [run_command ]; then
    echo "Updated variables.php successfully"
  else 
    echo "Did not update variables.php"
  fi
}

run_command() {
  perl -pi -e 's/(dbuser)(\s+)=\s.*;$/\1 = Config::get("db")["user"];/; s/(dbpass)(\s+)=\s.*;$/\1 = Config::get("db")["pass"];/; s/(dbname)(\s+)=\s.*;$/\1 = Config::get("db")["database"];/' "$CLI_CWD/variables.php"
}


if [ site_variables ]; then
  replace_variables
else 
  >&2 echo "Current directory ($(pwd)) is not a project root directory"
  exit 4
fi

here's the function where the if statement fails

replace_variables() {
  # perl -pi -e 's/(dbuser)(\s+)=\s.*;$/\1 = Config::get("db")["user"];/; s/(dbpass)(\s+)=\s.*;$/\1 = Config::get("db")["pass"];/; s/(dbname)(\s+)=\s.*;$/\1 = Config::get("db")["database"];/' "$CLI_CWD/variables.php"
  if [run_command ]; then
    echo "Updated variables.php successfully"
  else 
    echo "Did not update variables.php"
  fi
}

You can see that I commented out the one-liner just before the if statement, it works if I let that run and remove the if/else check.

here is the original file snippet before the update

//Load from Settings DB
    $dbuser     = 'username';
    $dbpass     = 'password';
    $dbname     = 'database_name';

here is the file snippet after the update would run

//Load from Settings DB
    $dbuser = Config::get("db")["user"];
    $dbpass = Config::get("db")["pass"];
    $dbname = Config::get("db")["database"];
John David
  • 388
  • 1
  • 4
  • 18
  • You probably get an error such as `-bash: [run_command: command not found` because you're missing a space after the opening `[` – but as the answer shows, you don't need `[ .. ]` at all here. – Benjamin W. May 19 '21 at 15:33
  • 1
    If you *did* get that error output, that should be part of the question as it's more helpful than "it didn't work". – Benjamin W. May 19 '21 at 15:33
  • Programmatically modifying your code can be a very powerful technique, but for mundane cases, it's often better to have everything in the source file and select which code to run based on a `#define` (in languages with such facilities) or a command-line argument or environment variable. – tripleee May 19 '21 at 16:01

1 Answers1

6

tl;dr and Solution

This usage of if with [ ] will not give you the result you expect.
What you're looking for

...
    if run_command; then
...

Longer explanation

Basics of if

  1. if is a shell feature
  2. based on the condition, it executes the body contained in between then and fi
  3. the "condition" that if checks is a command
  4. commands usually have a return/exit code. typically
    • 0 for success
    • 1 (common) and everything else for some error
      • e.g. 127 for command not found
  5. when the return/exit code is 0, the body is executed
  6. otherwise it is skipped; or control is passed to elif or else
  7. the syntax is if <command>; then...

Where does that [ ] come from?

  1. test is a command that can check file types and compare values
    • refer man test and help test (bash only)
  2. [ ... ] is a synonym for test
    • NB the brackets should be surrounded by spaces on both sides
    • if [ -f "/path/to/$filename" ]; then
      • exception: when terminated by new line or ; space not required
  3. test (or [ ]) evaluates expressions and cannot execute other commands or functions
  4. if [ expr ]; then is alternate syntax for if test expr; then

PS: good practice to "quote" your "$variables" when used with test or [ ]

PPS: [[ ... ]] is a different thing altogether. not POSIX; available only in some shells. take a look at this thread on the UNIX Stack Exchange

kevinnls
  • 728
  • 4
  • 19
  • 2
    thanks, that was way easy. If you can't tell, I'm new to Bash, that did the trick. Thank you. – John David May 19 '21 at 15:32
  • i'll be adding the explanation shortly. editing my answer to include it. if you think it all fits neatly, consider accepting the answer to let others know the solution :) – kevinnls May 19 '21 at 15:34