Failing to redirect error message in my command - linux

I'm a rookie in bash scripting, and here's basically my bash script:
Z=`diff -Z $ref_out $exec_out | grep "[<>]" | wc -l` 2>/dev/null
if [ $Z -gt 0 ]; then
echo "*** testcase: [ stdout - FAILED ]"
else
echo "*** testcase: [ stdout - PASSED ]"
fi
I would like to suppress the error message from diff such as:
diff: No such file or directory
This could either result from no $ref_out or $exec_out file, though I'm redirecting to /dev/null, this error message still shows up.
Any help?

You need diff's stderr to go to /dev/null, so it should instead be:
Z=`diff -Z $ref_out $exec_out 2> /dev/null | grep "[<>]" | wc -l`

Your redirection isn't working because it is being applied to the parent shell, not the subshell that runs the pipeline.
If you want to send the stderr of a bunch of commands to /dev/null, you could do it this way - I am using $() instead of backticks:
Z=$( { diff -Z $ref_out $exec_out | grep "[<>]" | wc -l; } 2>/dev/null )
Here, 2>/dev/null applies to all the commands inside { }.
There are many issues in your code. You could rewrite it in a better way:
if diff -Z "$ref_out" "$exec_out" 2>/dev/null | grep -q "[<>]"; then
echo "*** testcase: [ stdout - FAILED ]"
else
echo "*** testcase: [ stdout - PASSED ]"
fi
grep -q is a better way to do this check and you won't need a wc -l unless you want to know the exact number of matches
you need to quote your variables
if statement can include commands; you don't need to capture the output in order to use it in the if statement
You can use shellcheck to validate your shell script and see if you are making the usual mistakes that can break your code.

Related

Stop grep message from posting

I am working on a script that take 1 string argument and a file. I want it so that if a file is put in that doesn't exist, then it will display the "filename cannot be read" message.
That part does work however it also displays a "grep: grep.txt: No such file or directory" message. Is there any way to stop the grep message from posting and ending the script if the first if statement is true?
#! /bin/sh
if [ ! -f "$2" ]
then
echo "$0" cannot be read 1>&2
fi
if [ $# -eq 2 ]
then
grep "$1" $2
else
echo there is more or less than 2 arguments 1>&2
fi
Exit the script with a non-zero exit code to indicate failure and stop it from continuing on to the grep.
if [ ! -f "$2" ]
then
echo "$0" cannot be read 1>&2
exit 1
fi
You can add /dev/null in grep command it will suppress the error part.
grep "$1" $2 2>/dev/null
The > operator redirects the output usually to a file but it can be to a device. You can also use >> to append.
2> file redirects stderr to file
/dev/null is the null device it takes any input you want and throws it away. It can be used to suppress any output.
You could redirect all errors from grep, for example:
grep "$1" $2 2>/dev/null
(the 2> means redirect standard error, as opposed to standard output with > or 1>).
That introduces a race condition, however: if the file disappears while your script as running, it might still exist when you check that it exists, but be gone by the time grep runs.
You could handle that by checking the exit status...
grep "$1" $2 2>/dev/null
if [[ $? -gt 1 ]]; then
echo "grep failed unexpectedly" >&2
fi
IMHO, in this example it would be better to just let grep print the error.

Bash Script output is always 'ps' when piping to grep from ps regardless of PID results

given an array of pids and the code:
for i in ${listedPids[#]}
do
runningCheck="ps -u $USER | grep $i"
grepRes=(${runningCheck})
if [[ -n $grepRes ]]
then
echo $grepRes
echo $runningCheck
... code not related to the issue
fi
done
Regardless if those pids are active or not; I keep getting 'ps' from echo $grepRes while the output of echo $runningCheck shows up with the correct user name and pid. What am I missing?
Replace
"ps -u $USER | grep $i"
by
$(ps -u $USER | grep $i)
Command Substitution: Bash performs the expansion by executing your command and replacing the command substitution with the standard output of the
command, with any trailing newlines deleted.
I simplified your script and here's what it should look like.
for i in "${listedPids[#]}"
do
grepRes=$(ps --no-heading -p $i)
if [[ -n "$grepRes" ]]
then
echo "$grepRes"
... code not related to the issue
fi
done
An even shorter code could be written using while loop.
ps --noheading -p "${listedPids[#]}" | while read grepRes
do
echo "$grepRes"
... code not related to the issue
done
As alvits and l0b0 pointed out, I made a few syntax errors: grepRes=(${runningCheck}) when I just wanted to execute that line and not turn it to a list, and the fact pipes and redirects don't work in variables. In the end pgrep did the job as I just needed to continue looping till all the background processes ended.
Maybe you could try eval.
runningCheck1="ps -u $USER"
runningCheck2=" | grep $i"
echo $runningCheck1$runningCheck
eval $runningCheck1$runningCheck2

Searching a string in shell script

I am trying to learn shell script. So sorry if my question is so simple.
I am having a file called one.txt and if either strings 1.2 or 1.3 is present in the string then I have to display the success message else the failure message.
The code I tried is follows,
#!/bin/bash
echo "checking"
if grep -q 1.2 /root/one | grep -q 1.3 /root/one; then
echo " vetri Your NAC version"
fi
What I am doing wrong here ?
You can also include the OR in your grep pattern like so:
grep '1.2\|1.3' /root/one
details here
Update:
as twalberg pointed out in the comment, my answer was not precise enough. The better pattern is:
grep '1\.2\|1\.3' /root/one
Or even better, because more compact:
grep '1\.[23]' /root/one
You have to use ||
#!/bin/bash
echo "checking"
if grep -q 1.2 /root/one || grep -q 1.3 /root/one; then
echo " vetri Your NAC version"
fi
Single | operator is called pipe. It will pass the output of the command before | to the command after |.
It is better to join these these greps with | (OR operator):
grep '1.2\|1.3'
or
grep -E '1.2|1.3'
I guess the easier way to do this is to create a variable to check the count of occurrences:
#!/bin/bash
echo "checking"
CHECK=`egrep -c '1\.(2|3)' /root/one`
if [ "$CHECK" -gt 0 ]; then
echo "vetri Your NAC version"
fi

Bash Script : Unwanted Output

I have this simple bash script:
I run ns simulator on each file passed in argument where last argument is some text string to search for.
#!/bin/bash
nsloc="/home/ashish/ns-allinone-2.35/ns-2.35/ns"
temp="temp12345ashish.temp"
j=1
for file in "$#"
do
if [ $j -lt $# ]
then
let j=$j+1
`$nsloc $file > $temp 2>&1`
if grep -l ${BASH_ARGV[0]} $temp
then
echo "$file Successful"
fi
fi
done
I expected:
file1.tcl Successful
I am getting:
temp12345ashish.temp
file1.tcl Successful
When i run the simulator command myself on the terminal i do not get the file name to which output is directed.
I am not getting from where this first line of output is getting printed.
Please explain it.
Thanks in advance.
See man grep, and see specifically the explanation of the -l option.
In your script (above), you are using -l, so grep is telling you (as instructed) the filename where the match occurred.
If you don't want to see the filename, don't use -l, or use -q with it also. Eg:
grep -ql ${BASH_ARGV[0]} $temp
Just silence the grep:
if grep -l ${BASH_ARGV[0]} $temp &> /dev/null

Why linux redirect loss info?

I write a script like this:
#!/bin/bash
LOG_PATH=/root/cngiqos-log
LOG_NAME=term.log
TERM_PATH=/home/bnrcqos/qos_M11/term
test -d $LOG_PATH || mkdir -p $LOG_PATH
routeID='M11'
if [ `ps -ef | grep 'term$' | grep -v grep | wc -l` -gt 0 ]; then
echo $routeID' term process is already running'
else
cd $TERM_PATH
(nohup ./term > $LOG_PATH/$LOG_NAME 2>&1 &)
fi
And I input "tail -f /root/cngiqos-log/term.log" and see the log, the log loss info, the log only output part of a log and then don't output any more. But when I input "./term" and run it in fg, the output is fine.
Does any body know why? Is it a system bug?
Maybe you just get what you asked for? tail just gives the last 10 lines by default.

Resources