0

Thanks to: @Diego Torres Milano

https://stackoverflow.com/a/48569466/175063

#!/bin/bash
find /home -type f -name "wp-config.php" -print0 | while read -rd $'\x00' f
do
    cat '[%s]\n' "$f" | grep DB_NAME
done

But, seems to be missing something:

#!/bin/bash
find /home -type f -name "wp-config.php" -print0 | while read -rd $'\x00' f
do
    cat '[%s]\n' "$f" | grep DB_NAME | cut -d \' -f 4
done

With the results of:

./test.sh: line 5: unexpected EOF while looking for matching ``'
./test.sh: line 8: syntax error: unexpected end of file

Ultimately, I want something along the lines of:

#!/bin/bash
find /home -type f -name "wp-config.php" -print0 | while read -rd $'\x00' f
do
    printf '%s\n' "$f"
    WPDBNAME=`cat '%s\n' "$f" | grep DB_NAME | cut -d \' -f 4
    WPDBUSER=`cat '%s\n' "$f" | grep DB_USER | cut -d \' -f 4
    WPDBPASS=`cat '%s\n' "$f" | grep DB_PASSWORD | cut -d \' -f 4
    echo $WPDBNAME
    echo $WPDBUSER
    echo $WPDBPASS
done

Thanks!

Leptonator
  • 3,379
  • 2
  • 38
  • 51
  • 2
    Please take a look: http://www.shellcheck.net/ – Cyrus Feb 01 '18 at 23:09
  • 1
    There's an extra backtick at the end of -f 4` – LMC Feb 01 '18 at 23:14
  • 2
    If you just link to an older question of yours to explain what's going on, the current question isn't self-contained. To understand it, I have to go elsewhere first. You should describe what you're trying to do and what happened instead in the question itself. – Benjamin W. Feb 01 '18 at 23:44
  • 2
    Do you mean `printf` instead of `cat`? – Benjamin W. Feb 01 '18 at 23:45

2 Answers2

2

There are a number of problems here; to begin with, I'll second @Cyrus' recommendation of shellcheck.net -- it'll spot a number of common errors, including several in your script. Anyway, the problems I see are:

  • The error you're getting is due to unbalanced backquotes. The original version of the question had this line:

    cat '[%s]\n' "$f" | grep DB_NAME | cut -d \' -f 4`
    

    and that lone backquote at the end of the line will cause errors like the one you're getting. The edited version doesn't have that (and as a result will not give the reported error), but the "I want something along the lines of" script has lines like:

    WPDBNAME=`cat '%s\n' "$f" | grep DB_NAME | cut -d \' -f 4
    

    which has an unmatched backquote right after the =. My recommendation is to use $( ) instead of backquotes -- they're much easier to read (and hence harder to mess up), functionally equivalent, and don't have the subtle escaping issues that backquotes cause. So, you should use something like:

    WPDBNAME=$(cat '%s\n' "$f" | grep DB_PASSWORD | cut -d \' -f 4)
    
  • Except that that's still wrong. The '%s\n' part is a printf format string, which was needed in the example you copied, but is completely irrelevant here. If you give that argument to the cat command, it'll try to open a file named %s\n and fail. Just leave that off:

    WPDBNAME=$(cat "$f" | grep DB_PASSWORD | cut -d \' -f 4)
    
  • This next one isn't really a problem, so much as a general recommendation: anytime you see cat somefile | somethingcommand, the cat command isn't actually doing anything useful (it's known as a "useless use of cat"). It can be replaced by somecommand <somefile or, if the command supports input filenames directly, somecommand somefile. grep supports input filenames, so you can just use grep DB_PASSWORD "$f".

  • Actually, grep something | cut something can almost always be simplified by using awk instead. Just use /pattern/ to search for relevant lines, and print the relevant fields (using -F to define the field separator):

    WPDBNAME=$(awk -F \' '/DB_NAME/ {print $4}' "$f")
    
  • You aren't running into this problem, but using all-caps variable names can cause trouble and is generally considered a bad practice. There are a number of variables that have special meaning to the shell and/or other programs, and if you accidentally use one of those it can have bad/weird effects. The classic case is using PATH for something other than the list of places to look for executables, and then suddenly getting "command not found" errors.

    Just stick to lowercase or mixed-case variables, and you won't have to worry about this.

  • When you print the results, you don't double-quote the variables. Use echo "$wpdbname" instead of echo $wpdbname to prevent parsing oddities due to word splitting and glob expansion.

  • But actually, you don't need to capture the various parameters to variables at all, you can just print them directly. That is, replace:

    wpdbname=$(awk -F \' '/DB_NAME/ {print $4}' "$f")
    echo "$wpdbname"
    

    with:

    awk -F \' '/DB_NAME/ {print $4}' "$f"
    

Final script:

#!/bin/bash
find /home -type f -name "wp-config.php" -print0 | while read -rd $'\x00' f
do
    printf '%s\n' "$f"
    awk -F \' '/DB_NAME/ {print $4}' "$f"
    awk -F \' '/DB_USER/ {print $4}' "$f"
    awk -F \' '/DB_PASSWORD/ {print $4}' "$f"
done

Note: it'd sort of be possible to replace the separate awk commands with a single one that searched for & printed all three values. But that'd print them in the order they occur in the file, not necessarily the order you expect. So this is probably better.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
  • 3
    Re: single awk run -- you could print all the values from a single `END` block in chosen order. – Charles Duffy Feb 02 '18 at 03:16
  • @CharlesDuffy True, but that makes the `awk` script quite a bit more complicated. Unless the file's likely to be large (so scanning it 3 times takes noticeable time), I prefer the simple brute force approach. – Gordon Davisson Feb 02 '18 at 05:37
0

With guidance from responders here, I have been able to get to a resolution and below is now what is running as a cron job.

#!/bin/bash
# delete files older than 7 days
find /home/dummyacount/sqlbackups/ -type f -name '*.gz' -mtime +7 -exec rm {} \;
# set a date variable
DT=$(date +"%m-%d-%Y")
find /home -type f -name "wp-config.php" -print0 | while read -rd $'\x00' f
do
        printf '%s\n' "$f"
        WPDBHOST=$(grep DB_HOST '%s\n' "$f" | cut -d \' -f 4)
        WPDBNAME=$(grep DB_NAME '%s\n' "$f" | cut -d \' -f 4)
        WPDBUSER=$(grep DB_USER '%s\n' "$f" | cut -d \' -f 4)
        WPDBPASS=$(grep DB_PASSWORD '%s\n' "$f" | cut -d \' -f 4)
        mysqldump -q -u "$WPDBUSER" -h "$WPDBHOST" -p "$WPDBPASS" "$WPDBNAME" | gzip -9 > "/home/dummyaccount/sqlbackups/$DT-$WPDBNAME.sql.gz"
done

I also had to go back over to: https://tomjn.com/2014/03/01/wordpress-bash-magic/

to get some more of the syntax sorted out with mysqldump, but this is now working great.

Leptonator
  • 3,379
  • 2
  • 38
  • 51
  • `cat '%s\n' "$f"` is trying to read a file named `%s\n` before reading your `"$f"`. That's surely incorrect. It's also far less efficient than just running `grep DB_HOST "$f"`, or using the single-`awk` suggestions you were also given on the other question. – Charles Duffy Feb 02 '18 at 03:13
  • Also, this retains a bunch of quoting-related bugs that http://shellcheck.net/ will identify. Use it, trust it, &c. – Charles Duffy Feb 02 '18 at 03:14
  • (as for "working great" -- let me suggest running `exec 2>/tmp/my-cron.log` to dump its stderr to a logfile; you'll see, at minimum, an error message printed by every one of your unnecessary `cat` commands). – Charles Duffy Feb 02 '18 at 03:20