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. – Hauke Laging Apr 25 '20 at 3:57
  • @HaukeLaging That was how we were told to do it. – Yoshi24517 Apr 25 '20 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 '20 at 7:50

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 '20 at 4:09
  • 1
    It is called learning. – ctrl-alt-delor Apr 25 '20 at 6:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.