Bash Script error using grep - bash

I have the following script
var1=$(pwd)
echo $var1
if [ -e $var1 ]
then
echo present directory exists
if [ grep ^d\* | $(ls -al) ]
then
echo these are the directories in $var1
fi
else
echo failed
fi
Running this script gives the following output with errors
/home/user1/Desktop/workspace
present directory exists
ifelse.sh: 6: [: missing ]
ifelse.sh: 6: ifelse.sh: total: not found
Please explain the errors.
If possible give a resource where I can learn about about Bash script errors completely. Thanq

You have a syntax error in your grep.
You must interpolate (execute) the grep and pipe then evaluate the exit code of that command overall:
if [ $(grep ^d\* | $(ls -al)) ]

Related

shell script - too many arguments

I am unsure what is causing this error. Script continues to run and enters the "if" statement without issues.
"./test.sh: line 79: [: too many arguments"
if [ grep -Fq "variable=00000000000" /home/me/test.txt ] ; then #line 79
........
........
else
echo "hi"
fi
[ ... ] is not part of the syntax of an if statement. [ is a command name, that requires a final argument of ] to simulate the look of syntax.
Drop them if you want to run a different command whose exit status if should check.
if grep -Fq "..." /honme/me/test.txt; then
Simply use :
if grep -Fq "variable=00000000000" /home/me/test.txt; then
[...]
or
grep -Fq "variable=00000000000" /home/me/test.txt && echo 'true'
Explanations
Every command have a return code that you can display with :
true
echo $? # return 0, true in bash
false
echo $? # return 1: false in bash
It's named boolean logic

how to edit this code to show multiple files (it currently works with 1 file)?

I have created a shell script in order to find 2 files. While it works with 1 it does not work with 2 or multiple. Any help?
#!/bin/bash
FILENAME="abc"
if [ -f "${FILENAME}"* ]
then
echo "EXISTS"
else
echo "NOT EXISTS"
fi
Expected: EXISTS
Error:
./test.sh: line 5: [: abc1.sh: binary operator expected
NOT EXISTS
Error is here:
if [ -f "${FILENAME}"* ]
-f option accepts a single file. If there are more files that start
with $FILENAME then * is expanded and more than one file is passed
to -f. It's also reported by shellcheck:
$ ~/.cabal/bin/shellcheck test.sh
In test.sh line 5:
if [ -f "${FILENAME}"* ]
^-- SC2144: -f doesn't work with globs. Use a for loop.
If you want to check if there is at least one file that starts with
$FILENAME without using external tools such as find you need use
for loop like that:
#!/bin/bash
FILENAME="abc"
for file in "${FILENAME}"*
do
if [ -f "$file" ]
then
echo File exists
exit 0
fi
done
echo File does not exist.
exit 1
The simple way is to check if there less then 2 files with same name abc*:
#!/bin/bash
FILENAME="abc"
COUNT_FILES=$(find . -maxdepth 1 -name "$FILENAME*" -type f | wc -l)
if [[ $COUNT_FILES -lt 2 ]]
then
echo "NOT EXISTS"
else
echo "EXISTS"
fi
if ls /path/to/your/files* 1> /dev/null 2>&1
then
echo "files do exist"
else
echo "files do not exist"
fi
This is what I was looking for. What I wanted was a function that looks for single OR multiple files, which the code above performed perfectly. Thanks for the previous answers, much help.

How to syntax check a shell script before sourcing it?

I want to run this command source .env (sourcing a .env file) and if the .env file had some errors while sourcing. I want to show a message before the error output "Hey you got errors in your .env" else if there's no error, I don't want to show anything.
Here's a code sample that needs editing:
#!/bin/zsh
env_auto_sourcing() {
if [[ -f .env ]]; then
OUTPUT="$(source .env &> /dev/null)"
echo "${OUTPUT}"
if [ -n "$OUTPUT" ]; then
echo "Hey you got errors in your .env"
echo "$OUTPUT"
fi
}
You could use bash -n (zsh has has a -n option as well) to syntax check your script before sourcing it:
env_auto_sourcing() {
if [[ -f .env ]]; then
if errs=$(bash -n .env 2>&1);
then source .env;
else
printf '%s\n' "Hey you got errors" "$errs";
fi
fi
}
Storing the syntax check errors in a file is a little cleaner than the subshell approach you have used in your code.
bash -n has a few pitfalls as seen here:
How do I check syntax in bash without running the script?
Why not just use the exit code from the command source ?
You don't have to use bash -n for this because ...
If let's say your .env file contains these 2 invalid lines:
dsadsd
sdss
If you run your current accepted code using the example above:
if errs=$(bash -n .env 2>&1);
the above condition will fail to stop the file from sourcing.
So, you can use source command return code to handle all of this:
#!/bin/bash
# This doesn't actually source it. It just test if source is working
errs=$(source ".env" 2>&1 >/dev/null)
# get the return code
retval=$?
#echo "${retval}"
if [ ${retval} = 0 ]; then
# Do another check for any syntax error
if [ -n "${errs}" ]; then
echo "The source file returns 0 but you got syntax errors: "
echo "Error details:"
printf "%s\n" "${errs}"
exit 1
else
# Success here. we know that this command works without error so we source it
echo "The source file returns 0 and no syntax errors: "
source ".env"
fi
else
echo "The source command returns an error code ${retval}: "
echo "Error details:"
printf "%s\n" "${errs}"
exit 1
fi
The best thing with this approach is, it will check both bash syntax and source syntax as well:
Now you can test this data in your env file:
-
~
#
~<
>

Read unix log for message and then perform action

I am looking to create a shell script to read the message log and when finds the correct string perform an action. So far I have the following:
#!/bin/bash
string="ntp engine ready"
tail -n 0 -f /var/log/messages | \
while read LINE
do
echo "$LINE | grep -q $string"
if [ $? == 0];then
shttpclient "http://127.0.0.1/do/action"
fi
done
But, I get the following error:
grep: engine: No such file or directory
grep: ready: No such file or directory
Even when I see the logger has outputted ntp engine ready.
Firstly, you need to fix your quotes:
echo "$LINE" | grep -q "$string"
Secondly, you can simply do:
if echo "$LINE" | grep -q "$string"; then
rather than checking the return code $? manually. Remember that [ is a command too and if is just checking its return code.
If you do need to use [, remember that ] is an argument to the command so it is essential to surround it with spaces:
if [ $? = 0 ]
I have also removed the second = as it is a bash extension to support it. Actually you are doing an integer comparison, so really it should be one of the following:
if [ $? -eq 0 ] # POSIX compliant
if (( $? == 0 )) # bash arithmetic context
Alter the line as follows:
echo "$LINE" | grep -q "$string"
The quotes were not set correctly. Like when you execute that: grep -q ntp engine ready; ntp is the string to search and engine and ready are the files. It must look like: grep -q "ntp engine ready".

Check the output of a command in shell script

I'm writing a very simple shell scripts that would looked at the log of all failed tests, and print out all the name of all files in the current directory that are in the log
1 #! /bin/sh
2 for file in *
3 do
4 echo "checking: $file"
5 if [$(grep $file failed.txt -c) -ne 0]
6 then
7 echo "$file FAILED"
8 fi
9 done
When I execute it, I get this error:
line 6: [0: command not found
Does anyone have any idea why?
Thanks!!
[ is actually a command in linux (like bash or cat or grep).
$(grep $file failed.txt -c) is a command substitution which in your case evaluated to 0. Thus the line now reads [0 -ne 0], which is interpreted as run a program called [0 with arguments -ne 0].
What you should write instead is [ $(grep $file failed.txt -c) -ne 0 ]. Shell scripts require that there be spaces between the opening and closing square braces. Otherwise you change the command that is executed (the closing ] indicates that there are no more arguments to be read.
So now the command evaluates to [ 0 -ne 0 ]. You can try executing this in your shell to see what happens. [ exits with a value of 0 if the expression is true and 1 if it is false. You can see the exit value by echoing $? (the exit value of the last command to be run).
Instead of testing the count, you can test the return code of grep:
if grep -q $file failed.txt &>/dev/null
The script can be
#!/bin/sh
for file in *; do
echo "checking: $file"
grep failed.txt $file && echo "$file FAILED"
done
or, as an one-liner in user shell command history:
for file in *; do { echo "checking: $file" && grep failed.txt $file && echo "$file FAILED"; done
in man grep
EXIT STATUS
The exit status is 0 if selected lines are found, and 1 if not found. If an error occurred the exit status is 2. (Note: POSIX error handling code should check for '2' or greater.)

Resources