skip to Main Content

I’ve recently enrolled in a cybersecurity bootcamp and am having a little trouble figuring out where I’m going wrong writing this script with a grep command. I’m supposed to be pulling employee names from a schedule and the script is supposed to be able to accept 2 arguments representing a specific date and a specific time.
If I type the following line below, it successfully goes into the schedule file with the date of 0310 and pulls the name of the employee that was working at 5am.

find -type f -iname *0310* | grep "05:00:00 AM" ./* | awk -F" " '{print $5, $6}'

However when I turn it into a script like this:

#!/bin/bash 
find -type f -iname *$1* | grep $2 ./* | awk -F" " '{print $3, $4}'

And execute like this:

./script.sh 0310 "05:00:00 AM"

It gives me the following error code of the following and prints the employees who were working at 5am and also 5pm.

grep: AM: No such file or directory

I also get this error if I have another file with "0310" in the name

find: paths must precede expression: random_file_with_0310.txt' find: possible unquoted pattern after predicate -iname’?

Where am I going wrong with this script? Very new to BASH

2

Answers


  1. I think what you actually want is:

    #!/bin/bash 
    find -type f -iname "*${1}*" -exec awk  -v i="${2}" '$0 ~ i {print $5, $6}' "{}" + 
    

    Note that awk by default uses any number of whitespace (spaces, tabs) as a separator, so your field-separator may not actually be what you need/want, either.

    And a different approach:

    #!/bin/bash
    grep "${2}" $( find -type f -iname "*${1}*" ) | awk '{print $5, $6}'
    

    Slightly shorter (less typing), but more processes involved.

    Login or Signup to reply.
  2. You first problem is quoting.

    grep: AM: No such file or directory

    This is because what grep $2 ./* is running is

    grep 05:00:00 AM 
    

    making AM the file argument, followed by the expansion of ./* which is every file in whatever directory you ran the command from, which is also not what you want. You quoted it correctly in your CLI example, but you have to quote it in your script.

    grep "$2" ./* # still not looking at the right file
    

    This will pass the "5:00:00 AM" correctly, but isn’t going to search for it in the file(s) returned from find.

    Assuming there is only one file (I wouldn’t, but for simplicity’s sake…) – try

    file=`find -type f -iname *"$1"*` # note the quoting here also
    

    Personally, I prefer the improved syntax for the same thing –

    file="$(find -type f -iname *"$1"*)" # note the quoting here also
    

    If there is any chance you are going to get multiple files, then this is likely way beyond the scope of a bootcamp unless they are really doing it right, in which case c.f. this discussion of why filenames are not to be trusted.

    ANYWAY – once you have your filename, you still don’t need grep.

    awk -v ts="$ts" '$0~ts{print $5, $6}' "$file"
    

    or even, in one step,

    awk -v ts="$ts" '$0~ts{print $5, $6}' "$(find -type f -iname *"$1"*)"
    

    …but if you just felt the need to add a redundant pattern parser antipattern, then

    grep "$2" "$(find -type f -iname *"$1"*)" | awk '{print $5, $6}'
    

    A possible alternative, with no promises on performance…

    #/bin/bash
    ts="$1";                # save the string search pattern
    shift;                  # and shift it off the argument list
    shopt -s globstar;      # make ** match an arbitrary depth of folders
    awk -v ts="$ts" '$0~ts{print $5, $6}' "$@" # just use awk
    

    Call it with

    ./script.sh "05:00:00 AM" **/*0310* # pass search pattern first, then file list
    

    This should let the interpreter locate matching files for you and pass that list to the script. awk itself will only open the files it is passed as arguments, so you no longer need the find. awk can also pattern match for lines in those files, so you no longer need the separate grep.

    (This does run the possibility of returning directories and other weirdness as well as just plain files; we can add lines to accommodate that, but I’m trying to keep it fairly simple for the given problem.)

    I omitted the -F" " – you probably don’t need that, but be sure to test to see if it changes your actual output dataset. If what you literally meant was that you want every space to delimit a field, so that consecutive spaces mean empty fields, use -F'[ ]'.

    If that’s too fancy for your context, tink’s answer is probably what you want.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search