Reputation: 856
I have a file which contains:
2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \"restart\" -CS \"Undefined\" -RS \"Undefined\" -CT \"Undefined\" -RT \"Undefined\" --LogServer logserver:5610
As I'm trying to tail an executing log, I'm checking if the logfile contains the most current log. and see if this string exists. I tried with grep -F, grep -E, grep -FFxq So in short it comes down to this:
CurrentLog="2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \"restart\" -CS \"Undefined\" -RS \"Undefined\" -CT \"Undefined\" -RT \"Undefined\" --LogServer logserver:5610"
Please note that CurrentLog is filled like this:
CurrentLog=$(echo "$OutputTail" | jq ".entries[$EntryCount].log" | sed -e 's/^"//' -e 's/"$//' )
Meaning I can't just single quote.
grep -Fxq "$CurrentLog" "/usr/local/nagios/libexec/DAF-988e7506-36c3-47e3-8ef2-428309e2c7f7-670.log"
It seems like I need to escape both the '"' and the "\". How can I do this in one command? I was hoping the -F would not require me to add extra escaping?
Upvotes: 1
Views: 592
Reputation: 785721
To avoid escaping double quotes and backslashes you can use single quote around your variable declaration:
CurrentLog='2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \"restart\" -CS \"Undefined\" -RS \"Undefined\" -CT \"Undefined\" -RT \"Undefined\" --LogServer logserver:5610'
Test the variable content:
declare -p CurrentLog
declare -- CurrentLog="2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \\\"restart\\\" -CS \\\"Undefined\\\" -RS \\\"Undefined\\\" -CT \\\"Undefined\\\" -RT \\\"Undefined\\\" --LogServer logserver:5610"
Then use it as:
grep -qFx "$CurrentLog" file && echo "matched" || echo "nope"
matched
Another way is to use here-doc to declare your variable and not be worried about quoting:
read -r CurrentLog <<-'EOF'
2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \"restart\" -CS \"Undefined\" -RS \"Undefined\" -CT \"Undefined\" -RT \"Undefined\" --LogServer logserver:5610
EOF
Or better avoid creation of a separate variable and use process substitution:
read -r CurrentLog < <(jq -r --arg EntryCount "$EntryCount" '.entries[$EntryCount | tonumber].log' <<< "$OutputTail")
Upvotes: 1
Reputation: 754640
The backslash needs doubling up; the embedded double quotes need an escape (backslash) too. Hence you end up with \\\"
appearing in CurrentLog
.
CurrentLog="2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \\\"restart\\\" -CS \\\"Undefined\\\" -RS \\\"Undefined\\\" -CT \\\"Undefined\\\" -RT \\\"Undefined\\\" --LogServer logserver:5610"
Also, as Charles Duffy reminds me in his comment, it would be better to use single quotes around the assignment since you don't need any variables expanded or command substitutions made:
CurrentLog='2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A \"restart\" -CS \"Undefined\" -RS \"Undefined\" -CT \"Undefined\" -RT \"Undefined\" --LogServer logserver:5610'
Clearly, if you simplified the string for the question (e.g. the server
was actually expanded from a variable) then you'd need to revisit this. Also consider seriously the constructive use of .*
to match the quoted stuff. It's unlikely you have several logs with everything the same except that one has "restart"
and the other has "Undefined"
at the same point in the string. Using regexes is a fine art of balancing what's relevant and what's not.
But there comes a point (somewhere a bit before you reach this state), where it is better to but the string to be matched into a file and use the file and fixed string matching with grep
:
grep -F -f file-containing-pattern-line file-to-be-searched …
You then don't have to fight the shell's quoting and escaping mechanisms (or, at least, only while you're creating file-containing-pattern-line
). There's also the -x
option for 'exact matching of a whole line'.
Don't forget that here documents with quoted words are not interpreted:
cat > file-containing-pattern-line << 'EOF'
2016-08-15 21:02:59,007: 233-670-rundeck-dispatch-script.tmp.sh: Info: Arg: -H server -S SrvCtrl,SNMP -A "restart" -CS "Undefined" -RS "Undefined" -CT "Undefined" -RT "Undefined" --LogServer logserver:5610
EOF
You should also consider whether you really need to match on all of that. Would just the data/time be sufficient, or the date/time plus the script name (233-670-rundeck-dispatch-script.tmp.sh
). One of those is likely to be sufficient, and matching on just that greatly simplifies the reading of the code.
Upvotes: 2