1

I have the following shell script and they ask me to know how works and what the $1 and $2 parameters are.

#!/bin/bash

for i in `sort $1`; do   
    if grep $2 $i > /dev/null; then 
        echo A  
        cp $i /tmp  
        exit  
    fi  
done  
echo B;

My question is this: $1 can not be a directory because you can not sort on directories. Therefore, it must be a file. But the "for i in file" function implies that we will work for each line and the 'grep' tool does not work with lines.

I have considered that it should be a file that contains files, but for now I can only think of the tar files and it does not work with them.

Thanks!

5
  • 2
    Don'tReadLinesWithFor -- this code is intrinsically broken. See BashFAQ #1 for best practices around reading files line-by-line. Commented Mar 28, 2018 at 16:26
  • (That said, line-oriented files as a whole can't safely be used to store lists of arbitrary filenames, because files can have names that contain newlines. The only safe storage is for arbitrary filenames, like arbitrary C strings, environment variables, &c. is NUL-delimited). Commented Mar 28, 2018 at 16:27
  • 1
    Beyond that, it's not clear what you're actually asking. Is it for an explanation of how this code works? It doesn't work correctly -- it's broken. (In more ways than I covered already, too -- if you have * as a line in your file, it'll be replaced with a list of everything in your current working directory). Commented Mar 28, 2018 at 16:28
  • ...you say "my question is this", but what follows is a statement, not a question. Commented Mar 28, 2018 at 16:29
  • 1
    Also, see How to deal with questions of the type "I don't understand how this code works?" on Meta StackOverflow -- the consensus is that such questions should be closed as either "unclear what you're asking", or "too broad". Commented Mar 28, 2018 at 16:30

2 Answers 2

1

sort $1 most probably means that $1 contains the path to a file. The contents of the file are most probably paths to other files. In its unquoted form, it will be subject to word-splitting and glob expansion. This is either an oversight or intended behaviour (e.g. it would expand 'dat?.lst' to a list of files, as mentioned in the comments).

The for loop makes the assumption that none of these paths contain any awkward characters (spaces, glob characters like *), and goes through every word in the sorted output.

$2 (which again should really be "$2") is a pattern to search in the file $i. If the contents of the file match the pattern, then the file is copied to /tmp and the script exits.

Given the caveat of not working with filenames containing newlines, the simplest fix would be:

#!/bin/bash

sort "$1" | while read -r file; do
    if grep -q "$2" "$file" 2>/dev/null; then
        echo A  
        cp "$file" /tmp  
        exit  
    fi
done

This assumes that the script is passed the path to a file as the first argument, like:

/path/to/first/file
/path/to/second/file

And a regular expression as the second argument, with $s escaped to prevent the shell from attempting to expand them.

Sign up to request clarification or add additional context in comments.

4 Comments

Whether $1 or "$1" changes the semantics of the program. Maybe the writer want's to pass "dat?.lst" as parameter, which needs to be expanded?
@userunknown: that would then be a really awkward interface. If this is the case, the script should handle multiple arguments, and let the shell perform the globbing; it's then better to redesign the interface, have the pattern as the first argument, and the remaining arguments would then be the files. Usage would then be script thing-to-match file1 file2 file3, and allow script thing-to-match dat?.lst.
@userunknown: since the scripter didn't even bother quoting the expansion $2 for the grep statement, I'd argue that it's more an error from the scripter than an actual design feature.
@gniourf_gniourf: AFAIK, the question is an interview question, where you should answer what the script does - not how to improve it.
1
!/bin/bash

for i in `sort $1`  
do   
if grep $2 $i > /dev/null  
    then 
         echo A  
         cp $i /tmp  
         exit  
    fi  
done  
echo B;

Probably, the 1st param is filename or a list of filenames without whitespace, which itself contains a list of filenames. The $2 is a keyword which is searched for in these files, which were sorted by name first.

The first match leads to a copy of that file to /tmp - probably for further processing, and an echo message A and termination of the program. If no matching file is found, a different message is printed.

Note, that masking the $1 like this:

for i in $(sort "$1")
do   

will prevent the expansion of wildcards,

script "dat-?.lst" foobar

and possibly break the script, so I would be careful with suggestions to improve it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.