Redirect grep output to file - bash

I am not sure as to why that redirection provided in the code does not work. Every time I run the script, the output file is always empty. Does anyone have an idea on that?
Thanks.
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES
do
# echo "Looking in $i ..."
unzip -p $i | grep -i $LOOK_FOR > output #> /dev/null
if [ $? == 0 ]
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done

You may want to use >> (append) instead of > (overwrite) for redirection as:
unzip -p $i | grep -iF "$LOOK_FOR" >> output
Since you're executing this command in a loop and overwriting file output every time, it might be blank in the end if very last command with grep doesn't find any matching line in unzip output.

You have three problems
Don't try to parse the output of ls. Instead just use for i in plugins/*source*.jar The major reason is that your script will completely and utterly break on any files that have spaces in their names. See this link for a litany of reasons why not to parse ls
You need to use >> instead of > as the latter will overwrite the output file on each iteration of the loop. The former will append to it
Use more quotes! You'll want to quote your variables to make sure they aren't subjected to word splitting
Also, you can inline the if test. So putting it all together we have:
#!/bin/sh
LOOK_FOR="DefaultProblem"
for i in plugins/*source*.jar
do
# echo "Looking in $i ..."
if unzip -p "$i" | grep -i "$LOOK_FOR" >> output #> /dev/null
then
echo ">>>> Found $LOOK_FOR in $i <<<<"
fi
done

You can redirect the output of the entire loop:
#!/bin/sh
LOOK_FOR="DefaultProblem"
FILES=`ls plugins/*source*.jar`
for i in $FILES ; do
# echo "Looking in $i ..." 1>&2
unzip -p $i | grep -i $LOOK_FOR
if [ $? == 0 ] ; then
echo ">>>> Found $LOOK_FOR in $i <<<<" 1>&2
fi
done > output
Note that I've redirected the diagnostic messages to stderr.

Instead of a for loop and an if conditional you can do everything in one find command
find /path/to/plugins -name "*source*.jar" -exec sh -c 'unzip -l "{}" | grep -q DefaultProblem' \; -print

Related

How to match a folder name and use it in an if condition using grep in bash?

for d in */ ; do
cd $d
NUM = $(echo ${PWD##*/} | grep -q "*abc*");
if [[ "$NUM" -ne "0" ]]; then
pwd
fi
cd ..
done
Here I'm trying to match a folder name to some substring 'abc' in the name of the folder and check if the output of the grep is not 0. But it gives me an error which reads that NUM: command not found
An error was addressed in comments.
NUM = $(echo ${PWD##*/} | grep -q "*abc*"); should be NUM=$(echo ${PWD##*/} | grep -q "*abc*");.
To clarify, the core problem would be to be able to match current directory name to a pattern.
You can probably simply the code to just
if grep -q "*abc*" <<< "${PWD##*/}" 2>/dev/null; then
echo "$PWD"
# Your rest of the code goes here
fi
You can use the exit code of the grep directly in a if-conditional without using a temporary variable here ($NUM here). The condition will pass if grep was able to find a match. The here-string <<<, will pass the input to grep similar to echo with a pipeline. The part 2>/dev/null is to just suppress any errors (stderr - file descriptor 2) if grep throws!
As an additional requirement asked by OP, to negate the conditional check just do
if ! grep -q "*abc*" <<< "${PWD##*/}" 2>/dev/null; then

preventing wildcard expansion in bash script

I've searched here, but still can't find the answer to my globbing problems.
We have files "file.1" through "file.5", and each one should contain the string "completed" if our overnight processing went ok.
I figure it's a good thing to first check that there are some files, then I want to grep them to see if I find 5 "completed" strings. The following innocent approach doesn't work:
FILES="/mydir/file.*"
if [ -f "$FILES" ]; then
COUNT=`grep completed $FILES`
if [ $COUNT -eq 5 ]; then
echo "found 5"
else
echo "no files?"
fi
Thanks for any advice....Lyle
Per http://mywiki.wooledge.org/BashFAQ/004, the best approach to counting files is to use an array (with the nullglob option set):
shopt -s nullglob
files=( /mydir/files.* )
count=${#files[#]}
If you want to collect the names of those files, you can do it like so (assuming GNU grep):
completed_files=()
while IFS='' read -r -d '' filename; do
completed_files+=( "$filename" )
done < <(grep -l -Z completed /dev/null files.*)
(( ${#completed_files[#]} == 5 )) && echo "Exactly 5 files completed"
This approach is somewhat verbose, but guaranteed to work even with highly unusual filenames.
try this:
[[ $(grep -l 'completed' /mydir/file.* | grep -c .) == 5 ]] || echo "Something is wrong"
will print "Something is wrong" if doesn't find 5 completed lines.
Corrected the missing "-l" - the explanation
$ grep -c completed file.*
file.1:1
file.2:1
file.3:0
$ grep -l completed file.*
file.1
file.2
$ grep -l completed file.* | grep -c .
2
$ grep -l completed file.* | wc -l
2
You can do this to prevent globbing:
echo \'$FILES\'
but it seems you have a different problem

Bash "for file in" exception

I got this
for file in *; do
any command
done
What I want to do is add an exception to the "for file in *; do".
Any ideas?
If you wanted to skip files with a particular extension, for example, ".pl", you could do:
for file in *
do
[ "${file##*.}" != "pl" ] && echo $file
done
One way to do what I think you are asking is to loop through and check a file name with a if statement (or just grep -v the ls cmd):
for file in `ls`; do
if [ "$file" == "something" ]; then
# do something
else
# something else
fi
done
For example, you have files
$ ls -1 ./
./M2U0001.MPG
./M2U0180.MPG
./text
Exception file is M2U0180.MPG
$> filename="M2U0180.MPG"
And
$> for file in $(ls -1 ./* | grep --invert-match "${filename}" ); do echo $file; done
./M2U0001.MPG
./text
Weird solution done :)
use bash's extended globbing
shopt -s extglob
for f in !(excluded-file); do echo "$f"; done
A simple solution :
The following code snippet will print all the files in the pwd , that have a .py extension
for i in * ;do
if [[ $i == *.py ]];then
echo "$i"
fi
done

In a unix box, I am taking a list of files as input. If it is found, return the path otherwise return a message "filename file not found"

I have used the find command for this, but it doesnt return any message when a file is not found.
And I want the search to be recursive and return a message "not found" when a file is not found.
Here's the code I have done so far. Here "input.txt" contains the list of files to be searched.
set `cat input.txt`
echo $#
for i in $#
do
find $HOME -name $i
done
Try this:
listfile=input.txt
exec 3>&1
find | \
grep -f <( sed 's|.*|/&$|' "$listfile" ) | \
tee /dev/fd/3 | \
sed 's|.*/\([^/]*\)$|\1|' | \
grep -v -f - "$listfile" | \
sed 's/$/ Not found/'
exec 3>&-
open file descriptor 3
find the files
see if they're on the list (use sed to
send a copy of the found ones to file descriptor 3
strip off the directory name
get a list of the ones that don't appear
add the "Not found" message
close file descriptor 3
Output looks like:
/path/to/file1
/path/somewhere/file2
foo Not found
bar Not found
No loops necessary.
Whats wrong with using a script. I hope this will do.
#!/bin/bash -f
for i in $#
do
var=`find $HOME -name $i`
if [ -z "$var"]
then
var="File not found"
fi
echo $var
done
You can use the shell builtin 'test' to test the existence of a file. There is also an alternative syntax using square brackets:
if [ -f $a ]; then # Don't forget the semicolon.
echo $a
else
echo 'Not Found'
fi
Here is one way - create a list of all the files to grep against. If your implementation supports
grep -q otherwise use grep [pattern] 2&>1 >/dev/null....
find $HOME -type f |
while read fname
do
echo "$(basename $fname) $fname"
done > /tmp/chk.lis
while read fname
do
grep -q "^$fname" /tmp/chk.lis
[ $? -eq 0 ] && echo "$fname found" || echo "$fname not found"
done < /tmp/chk.lis
All of this is needed because POSIX find does not return an error when a file is not found
perl -nlE'say-f$_?$_:"not found: $_"' file

How to search an expression in a file from a bash script?

I have a bash script.
I need to look if "text" exists in the file and do something if it exists.
If you need to execute a command on all files containing the text, you can combine grep with xargs. For example, this would remove all files containing "yourtext":
grep -l "yourtext" * | xargs rm
To search a single file, use if grep ...
if grep -q "yourtext" yourfile ; then
# Found
fi
Something like the following would do what you need.
grep -w "text" file > /dev/null
if [ $? -eq 0 ]; then
#Do something
else
#Do something else
fi
grep is your friend here
You can put the grep inside the if statement, and you can use the -q flag to silence it.
if grep -q "text" file; then
:
else
:
fi
cat <file> | grep <"text"> and check the return code with test $?
Check out the excellent:
Advanced Bash-Scripting Guide
just use the shell
while read -r line
do
case "$line" in
*text* )
echo "do something here"
;;
* ) echo "text not found"
esac
done <"file"

Resources