Output list of for loop as variable - bash

I am trying to get the output of hostnames based on OS type (want only RedHat server hostnames) set as a variable.
but my code keeps spitting out the string RedHat along with each hostname.
minions=$(salt-run manage.up | cut -a " " -f2)
hosts=$(for minion in ${minions[#]}; do salt ${minion} grains.items | grep "os_family:" | grep RedHat && echo ${minion}; done)

By default grep will ouput the results of the pattern match.
If your version of grep supports it ... the -q flag will suppress the output:
... | grep -q RedHat && echo ${minion}; done)
Alternatively, redirect the output to /dev/null:
... | grep RedHat >/dev/null && echo ${minion}; done)

Related

bash get command that was used before pipe symbol

For a half-finished script that already uses the output of a program I also need the name and the parameters of the program that was used to pipe to my script.
So I run it like this:
yay something | ./myscript
Now I need to store "yay something" into a variable.
There is a way to to get previous runned commands or the current one by using set -o history -o histexpand and echo !! or echo $0 but that doesn't include what I wrote right before the pipe.
Maybe you would suggest to pass the name of the program and it's parameter to my script as parameters and then run it there but I don't want this (pass a command as an argument to bash script).
UPDATED SOLUTION (old below):
#!/bin/bash -i
#get processes
processes=$(> >(ps -f))
echo beginning:
echo "$processes"
#filter bin/bash -i
pac=$(echo "$processes" | sed '1,/bin\/bash -i/!d')
pac=$(echo "$pac" | tail -2 | head -1)
#kill
delete=$(echo $pac | grep -oP "(?<=$USER\s)\w+")
pac=$(echo "$pac" | grep -o -P '(?<=00:00:00).*(?=)')
echo "$delete"
kill -9 "$delete"
#print
echo " "
echo end:
echo "${pac:1}"
Note: When you use echo, man or cat then $pac will be empty.
OLD Text:
Thanks to Charles for his enormous effort and his link that finally led me to processes=$(> >(ps -f)).
Here a working example. You can e.g. use it with vi test | ./testprocesses (or nano or package helpers like yay or trizen but it won't work with echo, man nor with cat):
#!/bin/bash -i
#get processes
processes=$(> >(ps -f))
echo beginning:
echo $processes
#filter
pac=$(echo $processes | grep -o -P '(?<=CM).*(?=testprocesses)' | grep -o -P '(?<=D).*(?=testprocesses)' | grep -o -P "(?<=00:00:00).*(?=$USER)")
#kill
delete=$(echo $pac | grep -oP "(?<=$USER\s)\w+")
pac=$(echo $pac | grep -o -P '(?<=00:00:00).*(?=)')
kill -9 $delete
#print
echo " "
echo end:
echo $pac
The kill part is necessary to kill the vi instance else it will still be running and eventually interfer with future executions of the script.

Bash Subshell Variable Command not Found

I'm trying to run a command and interpret the results, but whatever I do I get a "command not found" error. Here's a representative version of my code:
devicename="emulator-5554"
search=$(adb devices | grep -w "$devicename" | grep -w device)
until $search; do
echo "Waiting..."
sleep 10
done
I've tried every variation that I can think of, including ...
search=$(adb devices | grep -w $devicename | grep -w device)
and
search=$(adb devices | grep -w ${devicename} | grep -w device)
..., but all return the same error.
How can I get the variable to be interpreted correctly?
The code you have runs the adb|grep|grep pipeline once only and stores the output in $search. Reading from $search doesn't re-run the pipeline.
Don't use variables to hold commands. Use functions.
search() {
adb devices | grep -w "$devicename" | grep -qw device
}
until search; do
echo "Waiting..."
sleep 10
done
Notice that I added -q to silence the final grep. You don't need to know what it found, just that it found something. Its exit code is all that matters; its output is irrelevant.
You could inline the function if you want.
until adb devices | grep -w "$devicename" | grep -qw device; do
echo "Waiting..."
sleep 10
done
Or you could make $devicename a parameter, if you wish.
search() {
adb devices | grep -w "$1" | grep -qw device
}
until search "$devicename"; do
echo "Waiting..."
sleep 10
done

Bash + SSH + Grep not generating output

I'm trying to use the script below to extract values from the df command on remote servers, then record to a log file. SSH keys are in place and no password is needed (this is not the problem).
It's getting hung up, however, and not spitting back output.
#!/bin/bash
PATH=/bin:/usr/bin:/usr/sbin
export PATH
SERVERLIST=/opt/scripts/server-list.dat
while IFS='|' read -u 3 hostname; do
echo evaluating $hostname...
SIZE=$(ssh $hostname | df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
echo $SIZE
done 3< $SERVERLIST
exit 0
You need to run df on the remote system, not pipe the output of an interactive ssh to it:
SIZE=$(ssh -n $hostname df -Pkhl | grep '/Volumes/UserStorage$' | awk '{print $2}')
Also, use the -n option to ssh to keep it from trying to read from stdin, which would consume the rest of the lines from the server list file.

Bash script doesn't work as cronjob

Hi i wrote the following bash script:
cat /home/xyz/wlandiscovery.sh
#!/bin/bash
DATE=`date +%d-%m-%Y__%H:%M:%S`
#Get the current standard interface e.g. eth0
INTERFACE=`route | grep '*' | awk '{print $8}'`
#Check if mac is available
if /usr/bin/arp-scan --interface $INTERFACE -l -r 5 | grep "xx:xx:xx:xx:xx:xx"
then
echo -e "$DATE AVAILABLE!" >> /home/xyz/wlandiscovery.log
else
echo -e "$DATE NOT AVAILABLE" >> /home/xyz/wlandiscovery.log
fi
exit 0
If i run this and the mac is available i get "AVAILABLE", if i disconnect the device it give "NOT AVAILABLE"...so run as expected.
But if i run it as Cronjob every 5 Minutes I get always "NOT AVAILABLE": (on a Debian system)
crontab -e
#......
*/5 * * * * /bin/bash /home/xyz/wlandiscovery.sh
Whats the problem here?
INTERFACE=`route | grep '*' | awk '{print $8}'`
On my system, route is /usr/sbin/route. /usr/sbin is most likely not in cron's PATH. Specify the full path:
INTERFACE=`/usr/sbin/route | awk '$2 == "*" {print $8}'`
Compare the command line output of the following on your Mac and Debian boxes:
INTERFACE=route | grep '*' | awk '{print $8}'
Is it the same? It should be in order to work.
Then, compare the command line output of:
/usr/bin/arp-scan --interface $INTERFACE -l -r 5 | grep "xx:xx:xx:xx:xx:xx"
Alright, now its working. seems that $PATH with crontab is not equal to $PATH in my Terminal prompt... if i do /sbin/route and /usr/bin/awk and /bin/grep it works.

bash changes execution order of command when run from jenkins

I am using git log to update a release_notes for my project. When I run the script below on my mac laptop everything works as expected, when I run on jenkins running on centos I see the following as the execution order:
script
...
FILE=RELEASE_NOTES
TMP_FILE=${FILE}.tmp
VERSION=$(cat pom.xml | grep "<version>" | head -n1 | sed -e "s/.*\>\(.*\)\<.*/\1/" | tr -d "\-SNAPSHOT")
NAME=$(cat pom.xml | grep "<artifactId>" | head -n1 | sed -e "s/.*\>\(.*\)\<.*/\1/")
echo "$NAME-${VERSION}" > ${TMP_FILE}
git log --pretty="%x09* [%h] %s." $(git describe --abbrev=0)..HEAD >> ${TMP_FILE}
echo "" >> ${TMP_FILE}
if [ -e $FILE ]; then
cat ${FILE} >> ${TMP_FILE}
fi
mv ${TMP_FILE} $FILE
...
jenkins output when run with #!/bin/bash -x
+ FILE=RELEASE_NOTES
+ TMP_FILE=RELEASE_NOTES.tmp
++ tr -d '\-SNAPSHOT'
++ head -n1
++ cat pom.xml
++ sed -e 's/.*\>\(.*\)\<.*/\1/'
++ grep '<version>'
+ VERSION='</'
++ head -n1
++ sed -e 's/.*\>\(.*\)\<.*/\1/'
++ cat pom.xml
++ grep '<artifactId>'
+ NAME='</'
+ echo '</-</'
++ git describe --abbrev=0
I cant figure out why the execution order is changing. Any thoughts?
I don't see any inconsistency. You have several commands running in subshells
(when it sets VERSION and NAME), and those commands have to be executed before
the variable is assigned to, so the /bin/bash -x output above is what I'd expect to see.
If you're talking about the order of the commands within each of those pipelines,
keep in mind that they're all run concurrently, and the exact startup order
might not be specified.
The order in which the individual commands in a pipeline are started (which is what set -x is showing you) doesn't matter. Data still flows from the left to the right. However, you can set the variables using a single call to grep instead of a pipeline. (This does assume GNU grep, however).
VERSION=$( grep -oP -m 1 '(?<=<version>).*(?=-SNAPSHOT)' pom.xml )
NAME=$( grep -oP -m 1 '(?<=<artifactId>).*(<=</artifactId)' pom.xml )
So on mac grep is BSD, linux GNU, so piping seems like it would be the best option to make sure it works on each environment. But found another solution: maven.
VERSION=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version | egrep -v "(^[INFO]|Download)" | tr -d "-SNAPSHOT")
NAME=$(mvn org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.artifactId | egrep -v "(^[INFO]|Download)")
This will let me get the version/name and works on both mac and linux.

Resources