string comparison is shell script - bash

I have a scenario to copy file from one server to another, for that i need to check any existing scp is in progress, have wrote a sample shell script but the condition is not being met even though syntax is correct, the main problem here is the output of ps command will gets stored in variable scpstat and the same compared for matching string in if statement, here I'm getting the output of the variable is different from executing outside of the script. can see it is formatted different in script execution when executing sh -x scpsamp.sh, why there is "sh" appended to the output, but while comparing without ps and assigning as scpstat='scp' i can able to get the condition correct, am i doing anything wrong while getting output in to the variable. please help
#!/bin/sh
scpstat=`ps -ef | grep scp | egrep -v 'grep|ssh' | awk '{print $8}')`
if [ "$scpstat" = "scp" ];
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi
sh -x output

It's notoriously difficult to extract information from the output of ps. If your system has pgrep, it's much easier:
if pgrep scp >/dev/null
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi

Related

Grep issue with if else statement in bash

I am trying to check whether a docker container exists using grep.
The following script signals an error exit during running when IMAGE is empty and is fine when IMAGE is set. I can't find out the cause.
#!/usr/bin/env bash
set -e
IMAGE=$(docker ps | grep my-dev-image)
if [[ -z "$IMAGE" ]]; then
echo "It is not there"
else
echo "It is there"
fi
When you use set -e in a script the shell will exit whenever a command fails. It interacts badly with your grep call because grep exits with an error code if it doesn't find a match. If grep fails then the entire IMAGE=$(...) assignment fails and the script exits instead of setting IMAGE to an empty string.
You can fix this by ensuring the assignment always succeeds. A common idiom for this is to append || :. Adding || cmd will run cmd whenever the command on the left fails. And : is a command that always succeeds. (Yes, it's a command name consisting of a single colon. Strange, but it's a legal identifier.)
IMAGE=$(docker ps | grep my-dev-image) || :
Alternatively, you could check grep's exit code directly by using it in the if statement. This is what I would do if I didn't care about grep's output:
if docker ps | grep -q my-dev-image; then
echo "It is there"
else
echo "It is not there"
fi

Script executes but fails to increment

So I have this shell script that I think should run a given number of times, sleep then resume, and output the results to a log file
#!/bin/bash
log=/path/to/file/info.log
a=$(COMMAND1 | cut -d : -f 2)
b=$(COMMAND2 | grep VALUE| cut -c 7,8)
for i in {1..4}
do
echo "Test" $i >> $log
date >> $log
echo $a >> $log
echo "$((-113 + (($b * 2)))) VALUE" >> $log
sleep 60
done
When I run ps -ef | grep scriptname.sh it seems the script does run. Executes once then the PID is gone as if the run has completed.
I have tested the script and know that it is running and capturing the data I want. But I do not understand why its not incrementing and not sure why its ending earlier than expected.
info.log output sample
Test {1..4}
DATE IN UTC
EXPECTED VALUE OF a
EXPECTED VALUE OF b
Note that the output is literally "Test {1..4}" not "Test 1" "Test 2" Test 3" and so on, as I would expect.
I have run the script as ./scriptname.sh & and as /path/to/file/scriptname.sh &
I have read that there is a difference in running the script with sh and bash though I dont fully understand what effect that would have on the script. I am not a software person at all.
I have tried to run the script with nohup to keep it running in the background if I close the terminal. I also thought the & in the command was supposed to keep the script running in the background. Still it seems the script does not continue to run
I previously asked this question and it was closed, citing that it was similar to a post about the difference between sh and bash...but thats not my main question.
also echo "$BASH_VERSION" returns nothing, a blank line. echo "$-" returns smi, and I have no idea what that means. but bash --version returns:
BusyBox v1.17.1 (2019-11-26 10:41:00 PST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
So my questions are:
If running the script with sh - is that done with ./scriptname.sh & and running the script with bash is /path/to/file/scriptname.sh &...and if so what effect does that have on how the script code is processed? that is - is using sh or bash. I do not fully understand the difference between the two
why does the script not continue to run when I close the terminal? This is my big concern. I would like to run this script hourly for a set period of time. Every time I try something and come back I get one instance in the log.
Neither brace expansion nor seq are part of the POSIX specification. Use a while loop.
log=/path/to/file/info.log
a=$(COMMAND1 | cut -d : -f 2)
b=$(COMMAND2 | grep VALUE| cut -c 7,8)
i=1
while [ "$i" -le 4 ]; do
printf 'Test %s\n' "$i"
date
printf '%s\n' "$a"
printf '%s\n' "$((-113 + (($b * 2)))) VALUE"
sleep 60
i=$((i+1))
done >> "$log"
(I suspect that you want to move the assignments to a and b inside the loop as well; right now, you are simply writing identical files to the log at each iteration.)

Not able to fetch the exit status of a multiple commands (separated by PIPE) which got assigned to a variable

Below is the sample script which i am trying to execute; but it fails to fetch the exit status of $cmd; is there any other way to fetch its exit status..!?
cmd="curl -mddddddd google.com"
status=$($cmd | wc -l)
echo ${PIPESTATUS[0]}
I know that, if i replace status=$($cmd | wc -l) with $cmd | wc -l , i could fetch the exit status of $cmd using PIPESTATUS. But in my case i have to assign it to a variable (example: status in above case).
Please help me here..!
Regards,
Rohith
What you're assigning to the status variable is not a status, but what $cmd | wc -l pipeline prints to standard output.
Why do you echo anyway? Try realstatus=${PIPESTATUS[0]}.
EDIT (After some digging and RTFMing...):
Just this -- realstatus=${PIPESTATUS[0]} -- doesn't seem to help, since $(command_substitution), which is in your code, is done "in a subshell environment", while PIPESTATUS is about "the most-recently-executed foreground pipeline"
If what you're trying to do in this particular case is to ensure the curl (aka $cmd) command was succesfull in the pipeline you should probably make use of pipefail option (see here).
If the output of the command is text and not excessively large, the simplest way to get the status of the command is to not use a pipe:
cmd_output=$($cmd)
echo "'$cmd' exited with $?"
linecount=$(wc -l <<<"$cmd_output")
echo "'wc' exited with $?"
What counts as "excessively large" depends on the system, but I successfully tested the code above with a command that generated 50 megabytes (over one million lines) of output on an old Linux system.
If the output of the command is too big to store in memory, another option is to put it in a temporary file:
$cmd >tmpfile
echo "'$cmd' exited with $?"
linecount=$(wc -l <tmpfile)
echo "'wc' exited with $?"
You need to be careful when using temporary files though. See Creating temporary files in Bash and How create a temporary file in shell script?.
Note that, as with the OP's example code, the unquoted $cmd in the code examples above is dangerous. It should not be used in real code.
If you just want to echo the pipe status, you can redirect that to stderr. But you have to do it in the subshell.
status=$($cmd | wc -l; echo ${PIPESTATUS[0]} >&2)
Or you can capture both variables from the subshell using read
read -rd $'\0' status pstatus <<<$($cmd | wc -l; echo ${PIPESTATUS[0]})

In unix how to find out if process running and return true/false?

I'm writing a unix shell script and need to check if there are currently running processes with "xyz" in their directory. If yes than continue to next command and show text like "Found It".
If not than don't continue and display text like "Process Not Found".
I tried something like this:
if ps -ef | grep xyz
then
echo "XYZ Process Found!"
else
echo "XYZ Process Not Found!"
fi
But it just showing me the processes and display "process found" even if there's no xyz process.
I believe you want to check the output of the command against a value using Command substition, from the linked bash-hackers wiki The command substitution expands to the output of commands. These commands are executed in a subshell, and their stdout data is what the substitution syntax expands to. Also, count the lines and remove grep. Something like,
if [[ $(ps -ef | grep xyz | grep -v grep | wc -l) != 0 ]]; then
echo "XYZ Process Found!"
else
echo "XYZ Process Not Found!"
fi
Edit
Based on the comments below, you should probably use
if [[ $(ps -ef | grep -c xyz) -ne 1 ]]; then
which is a lot easier to read.
When you run grep xyz, that process - grep xyz - is also running & thus shown in the output of ps -ef.
This running process command line contains xyz. Thus grep passes that line to output.
Hence you always get zero exit status - i.e. success.
2 Solutions:
use if ps -ef | grep '[x]yz'; then. (You may want to suppress grep output with -q)
The grep command being run is grep [x]yz. This gets printed in ps -ef output.
Obviously, grep filters out this line. [x]yz could be matched with \[x\]yz, not with [x]yz.
use if pgrep -f xyz >/dev/null; then
Check man pgrep for more details..
You can also use pgrep. From pgrep(1):
pgrep looks through the currently running processes and lists the
process IDs which match the selection criteria to stdout.
[...]
EXIT STATUS
0 One or more processes matched the criteria.
1 No processes matched.
2 Syntax error in the command line.
3 Fatal error: out of memory etc.
Example output:
[~]% pgrep xterm
18231
19070
31727
You can use it in an if statement like so:
if pgrep xterm > /dev/null; then
echo Found xterm
else
echo xterm not found
fi
Note: pgrep is not a standard utility (ie. it's not in POSIX), but widely available on at least Linux and I believe most BSD systems.
is_xyz_running() {
[ "$(pgrep xyz)" ] && echo true || echo false
}

shell script comparing two variables

I have created a script for updating some ipaddress in iptables. Hereby I'm describing the issues which I'm facing with that.
Issues:
Comparison not happening between two variables within a script
At the end of script i need to execute a command ie; service restart/stop etc and output of the commands should be visible while executing the script.
1) Here am comparing two variable strings:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
but there is no response/output while executing the above script. Here its not comparison is not happening..Kindly suggest a best solution to resolve this issue.
2) after executing the script I need to restart the iptables:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
service iptables restart
iptables -nvL
A script should display the output of the last two lines (commands). Kindly suggest me the best solution and how to do this in a best way.
That's very odd. This should work, so if it's not working you forgot to mention something important.
How is this script being executed? Do you simply type ./script or is it executed by some service (like cron)?
Here are some of suggestions to debug:
Sanity check: see if bash works (perhaps your login shell isn't bash, so you didn't notice). Run this at the terminal:
/bin/bash -c 'echo hello world'
It prints hello world, right? How about this:
/bin/bash -c 'BASE=172.31.0.0; CMD=172.31.1.0; if [[ "$CMD" == "$BASE" ]]; then echo "ip are same"; else echo "not matched"; fi'
If any of the above doesn't work, you have a problem with your bash installation.
Instead of executing your script with ./script.sh, run it like this:
/bin/bash script.sh
Nothing? Run this:
file script.sh
If it ends with something like "with CRLF line terminators", then cdarke nailed it: the file was created on Windows with an improper tool. Recreate it on Linux or use dos2unix. But anyway, I doubt it because with a CRLF-ending file I get this printed:
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
Instead of nothing at all.
Put those this line on the beginning of the file:
set -x
(below #!/bin/bash, if you have it). This ensures a debugging trace will be printed, showing each command as it is executed.
If still there is nothing shown.. put this at your script (below set -x if you put it):
touch /tmp/hi-this-is-strange
Then check if there is a /tmp/hi-this-is-strange file after you run the script.

Resources