I have an issue with a script.

Here is the code (with line numbers):

  1 function usage
  2 {
  3  echo "usage: $0 filename ..."
  4  echo "ERROR: $1"
  5 }
  7 if [ $# -gt 0 ]
  8 then name=(name hidden for security purposes)
  9  echo $name
 10  date
 11  for starting_data
 12  do
 13   echo ""
 14   if [ -f $1 ]
 15   then if !(grep -v "[0-9]\{3\}-[0-9]\{2\}-[0-9]\{4\}, [a-zA-Z]\+, [a-zA-Z]\+" $1)
 16    then starting_data=$1
 17     echo "$1"
 18     sed '/^id/ d' $starting_data > rawdata
 19     cut -f1 -d, rawdata > rawdata.col1
 20     cut -f2 -d, rawdata > rawdata.col2
 21     cut -f3 -d, rawdata > rawdata.col3
 22     sed 's/-//' rawdata.col1 > raw1
 23     sed 's/-//' raw1 > rawfinal1
 24     sed 's/$/:/' rawdata.col2 > raw2
 25     sed 's/ //' raw2 > rawfinal2
 26     sed 's/ //' rawdata.col3 > raw3
 27     more raw3 > rawfinal3
 28     paste -d\  rawfinal3 rawfinal2 rawfinal1 > final
 29     more final
 30     rm rawdata rawdata.col1 rawdata.col2 rawdata.col3 raw1 raw2 raw3 rawfinal1 rawfinal2 rawfinal3 final
 31     shift
 32    else usage "Invalid data in $1"
 33     shift
 34    fi
 35   else usage "Could not find file $1"
 36    shift
 37   fi
 38  done
 39 else usage "Please enter a filename."
 40 fi

The key line I am having trouble with is line 15. I want it to find lines that do not match the regex, but do not make an output. In my homework, I am required to use grep -v to find these lines, but all it does is output the lines that do not match the regex. What I want it to do is display the usage statement, and the error about invalid file data, if it finds a line that does not match the expected grep statement. (The regex listed does match correctly in the correct files, do not worry about that.)

In short, what I want to do, is if grep -v finds a line that does not match the regex in a file, I want it to not display the output, and instead, only display my error statement.

What I get when I type ./[scriptname] raw_data more_bad_data more_data bad_data raw_data2 additional_bad_data

I get (Note: anything with bad_data in the name is supposed to display only the usage statement and an error):

(name hidden for security purposes)
Fri Apr 24 20:23:54 PDT 2020

[correct output]

[more_bad_data grep -v output]
usage: ./hw12.sh filename ...
ERROR: Invalid data in more_bad_data

[correct output]

[bad_data grep -v output]
usage: ./hw12.sh filename ...
ERROR: Invalid data in bad_data

[correct output]

[additional_bad_data grep -v output]
usage: ./hw12.sh filename ...
ERROR: Invalid data in additional_bad_data

What is currently displayed in line 15 is what I have tried so far for that statement, and I tried it without the parentheses and the exclamation point.

Any help?

  • 1
    All those cut, sed, and paste calls could be replaced by a single awk call. Apr 25, 2020 at 3:57
  • @HaukeLaging That was how we were told to do it.
    – Yoshi24517
    Apr 25, 2020 at 4:03
  • @Yoshi24517 Calling sed and cut so many times inside a loop is definitely to be avoided, no matter what you have been taught by some professor. awk would be a much better fit and you could probably replace that long section of code within the inner if statement with a single call to awk. Also, more is a pager, i.e. a utility for displaying text for looking at. To copy files, use cp.
    – Kusalananda
    Apr 25, 2020 at 7:50

1 Answer 1


You can either use the exit code

if grep -q -v ...
if grep -v ... >/dev/null 2>&1

The first command would be more efficient as grep -q stops reading the input file as soon as it finds a match. This would potentially make a big difference if you grep across large files.

Or (worse) detect that there is output:

if [ -n "$(grep -v ...)" ]; then
  • Thank you! (Why is it always one little character I'm missing always? This happens to me every time >:( )
    – Yoshi24517
    Apr 25, 2020 at 4:09
  • 1
    It is called learning. Apr 25, 2020 at 6:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .