Further to Don's remarks, if you are using file name expansion with the for loop,
The first attempt might look like this:
for file in file_20160*.lis
do
grep "$file" bplist.txt >>filetodelete.txt
done
It is important to test for the case when there are zero files that fit the pattern, otherwise you end up with an a variable that contains file_20160*.lis
, which would then become a regular expression, since that is what grep, like so:
grep file_20160*.lis bplist.txt >>filetodelete.txt
which would then delete any file names that start with "file_2016" followed by zero or more zeroes and ".lis" from the file..
Now probably those files do not exist in your case, but it is best to avoid a possible loop hole altogether, by testing if a file exists and use string matching instead of regex matching, using grep's -F parameter. To avoid partial file name matches (where the pattern or string that grep is looking for is a subset of the filename) another important parameter would be the -x option, which forces line matches. A third thing would be to avid the possibility that files that start with a -
sign could be interpreted as an option flag to grep. One way to stop this is by using the --
flag. Because you file pattern starts with file
that will not be an issue here, but it is good practice to do that anyways, so that in future if you ever change the pattern so that it starts with an *
, this will not break things.
So then it becomes:
for file in file_20160*.lis
do
if [ -f "$file" ]; then
grep -Fx -- "$file" bplist.txt >>filetodelete.txt
fi
done
Now that last thing here is that you are appending to the file here, probably out of necessity, otherwise the file would be overwritten with very loop. An alternative would be to redirect the loop itself so the file would only be opened once and you do not have to delete the file prior to running the loop:
for file in file_20160*.lis
do
if [ -f "$file" ]; then
grep -Fx -- "$file" bplist.txt
fi
done > filetodelete.txt
One last thing. This is still an expensive way to do it because an external program in a subshell is used to perform the operations for every iteration in the for loop, which is resource intensive.
An alternative would be to use a pipe ( |
) and grep's -
operator for stdin, which most grep's (but not all) will honor, together with the file flag -f
ls file_20160*.lis | grep -Fxf - -- bplist.txt > filetodelete.txt
if there are not too many files in the directory.
Or use the more robust:
for file in file_20160*.lis
do
if [ -f "$file" ]; then
printf "%s\n" "$file"
fi
done |
grep -Fxf - -- bplist.txt > filetodelete.txt
Since the -
operator for stdin is not universally supported in grep, another way would be to use process substitution ( <( ... )
) that is used in for modern bash, ksh93 or zsh:
grep -Fxf <(ls file_20160*.lis) -- bplist.txt > filetodelete.txt
if there are not too many files in the directory.
Or again the more robust variety:
grep -Fxf <(
for file in file_20160*.lis
do
if [ -f "$file" ]; then
printf "%s\n" "$file"
fi
done
) -- bplist.txt > filetodelete.txt