bash variable as a command: echo the command before execution and save the result to a variable - bash

I am executing a chain of curl commands:
I need to echo the command before the execution.
Execute the command and save the result to a bash variable.
Get values from the result of the execution and execute the next curl with that values.
This is how it looks like:
# -----> step 1 <-----
URL="https://web.example.com:8444/hello.html"
CMD="curl \
--insecure \
--dump-header - \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
JSESSIONID=$(echo $OUT | grep JSESSIONID | awk '{ s = ""; for (i = 2; i <= NF; i++) s = s $i " "; print s }' | xargs)
# Location: https://web.example.com:8444/oauth2/authorization/openam
URL=$(echo $OUT | grep Location | awk '{print $2}')
# -----> step 2 <-----
CMD="curl \
--insecure \
--dump-header - \
--cookie \"$JSESSIONID\" \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
...
# -----> step 3 <-----
...
I only have a problem with the step 2: save the full result of the curl command to a variable in order to I can parse it.
I have tried it many different way, non of them works:
OUT="eval \$CMD"
OUT=\$$CMD
OUT=$($CMD)
...
What I missed?

For very basic commands, OUT=$($CMD) should work. The problem with this is, that strings stored in variables are processed differently than strings entered directly. For instance, echo "a" prints a, but var='"a"'; echo $a prints "a" (note the quotes). Because of that and other reasons, you shouldn't store commands in variables.
In bash, you can use arrays instead. By the way: The naming convention for regular variables is NOT ALLCAPS, as such names might accidentally collide with special variables. Also, you can probably drastically simplifiy your grep | awk | xargs.
url="https://web.example.com:8444/hello.html"
cmd=(curl --insecure --dump-header - "$url")
printf '%q ' "${cmd[#]}"; echo
out=$("${cmd[#]}")
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
jsessionid=$(awk '{$1=""; printf "%s%s", d, substr($0,2); d=FS}' <<< "$out")
# Location: https://web.example.com:8444/oauth2/authorization/openam
url=$(awk '/Location/ {print $2}' <<< "$out")
# -----> step 2 <-----
cmd=(curl --insecure --dump-header - --cookie "$jsessionid" "$url")
printf '%q ' "${cmd[#]}"; echo
out=$("${cmd[#]}")
# -----> step 3 <-----
...
If you have more steps than that, wrap the repeating part into a function, as suggested by Charles Duffy.

Easy Mode: Use set -x
Bash has a built-in feature, xtrace, which tells it to log every command to the file descriptor named in the variable BASH_XTRACEFD (by default, file descriptor 2, stderr).
#!/bin/bash
set -x
url="https://web.example.com:8444/hello.html"
output=$(curl \
--insecure \
--dump-header - \
"$url")
echo "Output of curl follows:"
echo "$output"
...will provide logs having the form of:
+ url=https://web.example.com:8444/hello.html
++ curl --insecure --dump-header - https://web.example.com:8444/hello.html
+ output=Whatever
+ echo 'Output of curl follows:'
+ echo Whatever
...where the + is based on the contents of the variable PS4, which can be modified to have more information. (I often use and suggest PS4=':${BASH_SOURCE}:$LINENO+' to put the source filename and line number in each logged line).
Doing It By Hand
If that's not acceptable, you can write a function.
log_and_run() {
{ printf '%q ' "$#"; echo; } >&2
"$#"
}
output=$(log_and_run curl --insecure --dump-header - "$url")
...will write your curl command line to stderr before storing its output in $output. Note when writing that output that you need to use quotes: echo "$output", not echo $output.

I guess OUT=$(eval $CMD) will do what you want.

Related

Check return code in bash while capturing text

When running an ldapsearch we get a return code indicating success or failure. This way we can use an if statement to check success.
On failure when using debug it prints if the cert validation failed. How can I capture the output of the command while checking the sucess or failure of ldapsearch?
ldapIP=`nslookup corpadssl.glb.intel.com | awk '/^Address: / { print $2 }' | cut -d' ' -f2`
server=`nslookup $ldapIP | awk -F"= " '/name/{print $2}'`
ldap='ldapsearch -x -d8 -H "ldaps://$ldapIP" -b "dc=corp,dc=xxxxx,dc=com" -D "name#am.corp.com" -w "366676" (mailNickname=sdent)"'
while true; do
if [[ $ldap ]] <-- capture text output here ??
then
:
else
echo $server $ldapIP `date` >> fail.txt
fi
sleep 5
done
As #codeforester suggested, you can use $? to check the return code of the last command.
ldapIP=`nslookup corpadssl.glb.intel.com | awk '/^Address: / { print $2 }' | cut -d' ' -f2`
server=`nslookup $ldapIP | awk -F"= " '/name/{print $2}'`
while true; do
captured=$(ldapsearch -x -d8 -H "ldaps://$ldapIP" -b "dc=corp,dc=xxxxx,dc=com" -D "name#am.corp.com" -w "366676" "(mailNickname=sdent)")
if [ $? -eq 0 ]
then
echo "${captured}"
else
echo "$server $ldapIP `date`" >> fail.txt
fi
sleep 5
done
EDIT: at #rici suggestion (and because I forgot to do it)... ldap needs to be run before the if.
EDIT2: at #Charles Duffy suggestion (we will get there), we don't need to store the command in a variable.

unable to print the second variable data in the shell script

Esteemed colleagues,
I have written a small code where i'm storing some command output into two different variables and aspiring those two values to be printed under into different columns called "PreferredList IP's" & "DefaultServerList IP's".
there are Variables PLIST & DLIST,So, when i'm running the script i only see output under the first column and unable to get the data under second column.
This looks weird to me, i don't know where i'm doing mistake..please do correct me..
#!/bin/sh
set -f # to prevent filename expansion
printf "=%.0s" $(seq 1 50)
printf "\n"
printf "%-30s : %10s\n" "PreferredList IP's" "DefaultServerList IP's" # print header
printf "=%.0s" $(seq 1 50) # print separator
printf "\n" # print newline
PLIST="$(ldapsearch -h mylap -x -b "ou=profile,o=cadence.com" "cn=*" preferredserverlist -LLL | awk '/preferredserverlist: / {print $2}')"
DLIST="$(ldapsearch -h myldap -x -b "ou=profile,o=cadence.com" "cn=*" defaultserverlist -LLL | awk '/defaultserverlist: / { print $2 }')"
printf "%-30s : %10s\n" "$PLIST" "$DLIST"
RESULT: while using debug mode, I saw the problem is both the varibale output coming into first column.
======================================================
PreferredList IP's : DefaultServerList IP's
========================================================
123.18.8.15
123.18.8.16
192.10.167.9
192.10.167.8
123.18.8.16
10.218.88.38
Below is the ldapsearch command output sample:
dn: cn=india, ou=profile, o=cadence.com
preferredServerList: 123.18.8.15 123.18.8.16
defaultServerList: 123.18.8.16 123.18.8.15
dn: cn=japan, ou=profile, o=cadence.com
preferredServerList: 192.10.167.9 192.10.167.8
defaultServerList: 123.18.8.16 10.218.88.38
$ ldapsearch -h myldap -x -b "ou=profile,o=cadence.com" "cn=*" preferredserverlist -LLL | awk '/preferredserverlist: / {print $2}' | head -2
123.18.8.15
123.18.8.16
$ ldapsearch -h myldap -x -b "ou=profile,o=cadence.com" "cn=*" defaultserverlist -LLL | awk '/defaultserverlist: / { print $2 }' | head -2
123.18.8.16
10.218.88.38
It seems like the real problem you have is formatting your columns.
You have two list of IPs stored in PLIST and DLIST as strings, separated by newlines. When you type
printf "%-30s : %10s\n" "$PLIST" "$DLIST"
It will not automatically format those into columns for you.
You really need to change the way you're parsing your LDAP results. /bin/sh is really not inherently suited to this kind of output formatting.
If you have the option of using bash (version > 4), use mapfile and restructure your program like this:
#!/bin/bash
set -f # to prevent filename expansion
# Store the output of the ldapsearches in arrays using mapfile.
mapfile -t PLIST < <(ldapsearch -h mylap -x -b "ou=profile,o=cadence.com" "cn=*" preferredserverlist -LLL | awk '/preferredserverlist: / {print $2}')
mapfile -t DLIST < <(ldapsearch -h myldap -x -b "ou=profile,o=cadence.com" "cn=*" defaultserverlist -LLL | awk '/defaultserverlist: / { print $2 }')
# Count the number of elements in each array.
count_x=${#PLIST[#]}
count_y=${#DLIST[#]}
# Print the count for debugging.
echo $count_x
echo $count_y
# Find out which of the two arrays is larger in size, assuming that's a possibility, pick the length of the bigger one.
if [[ $count_x -lt $count_y ]]
then
count=$count_y
else
count=${count_x}
fi
printf "=%.0s" $(seq 1 50)
printf "\n"
printf "%-30s : %10s\n" "PreferredList IP's" "DefaultServerList IP's" # print header
printf "=%.0s" $(seq 1 50) # print separator
printf "\n" # print newline
# Use an index 0 < i <= count, to loop over the arrays simultaneously.
for i in $(seq $count);
do
printf "%-30s : %10s\n" "${PLIST[i-1]}" "${DLIST[i-1]}"
done
This uses bash's mapfile to store the output of the ldap search commands in an indexed array and prints it out in a formatted column.
As a test, I wrote this out and replaced your ldap commands with mock seq calls to generate numbers. Here's a sample run.

Can you set multiple cURL --write-out variables to bash variables in a single call

I need to set or access multiple cURL variables so I can access them later in a script. For example:
curl -s --write-out "%{http_code} | %{local_ip} | %{time_total}" "http://endpoint.com/payload"
Now how can I access http_code or local_ip to do things like add them to an bash array, etc? Is the only option to grep them out of the response?
You can pipe your curl command to a read command :
curl -s --write-out "write-out: %{http_code} | %{local_ip} | %{time_total}\n" "http://yahoo.com" | \
sed -n '/^write-out:/ s///p' | \
while IFS='|' read http_code local_ip time_total;
do
printf "http_code: %s\nlocal_ip: %s\ntotal_time: %s\n" $http_code $local_ip $time_total;
# or in an array
curlvars=($http_code $local_ip $time_total)
for data in "${curlvars[#]}"
do
printf "%s | " $data
done
done
I added a \n to the write-out string to allow process it as a line.
The sed command extract the write-out line from the curl output.
In the read command you can define a separator and assign all parsed strings to vars.

curl in bash script vs curl one liner

This code ouputs a http status of 000 - which seems to indicate something didn't connect properly but when I do this curl outside of the bash script it works fine and produces a 200 so something with this code is off... any guidance?
#!/bin/bash
URLs=$(< test.txt | grep Url | awk -F\ ' { print $2 } ')
# printf "Preparing to check $URLs \n"
for line in $URLs
do curl -L -s -w "%{http_code} %{url_effective}\\n" $line
done
http://beerpla.net/2010/06/10/how-to-display-just-the-http-response-code-in-cli-curl/
your script works on my vt.
I added in a couple of debugging lines, this may help you to see where any metacharacters are getting in, as I would have to agree with the posted coments.
I've output lines in the for to a file which is then printed out with od.
I have amended the curl line to grab the last line, just to get the response code.
#!/bin/bash
echo -n > $HOME/Desktop/urltstfile # truncate urltstfile
URLs=$(cat testurl.txt | grep Url | awk -F\ ' { print $2 } ')
# printf "Preparing to check $URLs \n"
for line in $URLs
do echo $line >> $HOME/Desktop/urltstfile;
echo line:$line:
curl -IL -s -w "%{http_code}\n" $line | tail -1
done
od -c $HOME/Desktop/urltstfile
#do curl -L -s -w "%{http_code} %{url_effective}\\n" "$line\n"

Simple Server using netcat and curl

I am trying to build a simple server with netcat and curl.
netcat gets data coming from a port and then runs a curl command as follows to send the data to a webservice.
nc -l -k 2233 | while read x ; do curl -X POST -H "Content-Type: application/json" -d '{"DATA": `echo $x` }' https://example.com/FEP ; done
for some reason, the echo $x is not being evaluated to the read value.
You need to move $x out of the ' delimited string, e.g. -d '{"DATA":"'$x'" }'.
Special characters in single quoted strings are never honored.
See the example:
x=text
echo single: '$x'
echo double: "$x"
prints
single: $x
double: text
There is no need to echo $x; just use
curl [options] '{"DATA": '$x' }' https://example.com/FEP; done

Resources