Converting a working command into shell script file which gets arguments

Hi my working command is:

grep -l "my text" file*.ext|xargs ls -lart

this command is very useful for me and I wanted to create a shell file which does it with fewer typing, like this:

fn "my text" file*.ext

I came to this shell script file:

grep -l "$1" "$2"|xargs ls -lart

which is not working, even the first part is not working:

grep -l "$1" "$2"

which returns null

Answer

Your script will need to take more than two arguments.

Before the shell executes grep in the command

grep -l "my text" file*.ext

the filename globbing pattern file*.ext is expanded to all matching filenames. The command line that is finally run will therefore be

grep -l "my text" file1.ext file2.ext file3.ext

(if those are the files that matches the pattern)

Therefore, your script may look like

#!/bin/sh

pattern=$1
shift

grep -l -e "$pattern" "[email protected]" | xargs ls -lrt

Here, the pattern is saved into a variable, and then shifted off the list of command line arguments. The remaining arguments is a list of filenames (if the filename globbing pattern on the command line matches) and is available in "[email protected]".

Make sure you double quote [email protected]. This will make [email protected] expand to the list of individually quoted command line arguments.

I’ve removed the -a option from ls as it’s not needed when giving explicit filenames to list. I’m also using grep with -e to specify the pattern, as a pattern with an initial dash (-) may otherwise confuse grep.


If it wasn’t for the sorting, I would have suggested the following find command instead of your pipeline (correctly handles filenames with spaces and newlines):

find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

This looks for files with names matching what’s in $filepattern, and with contents matching what’s in $pattern, and then produces ls -l-like output. The search is performed recursively in the current directory.

As part of a script:

#!/bin/sh

pattern=$1
filepattern=$2

find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

This script would need to be called in such a way that the filename globbing pattern isn’t expanded by the shell when calling it:

$ ./script.sh 'my text' 'file*.ext'

Leave a Reply

Your email address will not be published. Required fields are marked *