Find all files ending in extension in bash
Find all files ending in extension in bash
Write a bash script accepting two arguments: directory and extension.
The script must print to stdout the path of all files in directory (and,
recursively, its sub-directories) with a name ending with extension.
So far I have:
find directory -type f -name ' *.extension *
when I give it 2 args it doesn't seem to find anything.
*
3 Answers
3
This script should do the trick:
#!/bin/bash
find "$1" -type f -name "*.$2"
Examples to run the script:
/bin/bash script.sh /srv/directory css
/bin/bash script.sh '/srv/directory with space' css
In this answer, I'm just giving some explanation for Viktor's code.
This explanation might help those of you who are learning bash
. Viktor updated his answer after I posted the "space issue" part and before I finished writing and saving this explanation. That's what I hoped for.
bash
It is very concise, and there are great explanations. The original code was:
#!/bin/bash
#@filename: script.sh
find $1 -type f -name "*.$2"
It sounds like the question came from some kind of assignment, and I imagine that this original code might fulfill the assignment's expectations. It will probably also work with most programs you will write, which is especially important if the question did not come from an assignment.
I often develop on Windows or Cygwin, so I run into paths and filenames that have spaces. If I use @Viktor's code on Cygwin (note that the same behavior happens when I use Viktor's code on linux)
$ pwd
/home/me
#Write the program
$ vim script.sh
#view the program
$ cat script.sh
#!/bin/bash
find $1 -type f -name "*.$2"
#Create a path with spaces in one of the directory names
#Name it after Viktor, for the great answer
CORP+dblack@CAP-D-ENG-INT3 ~
$ mkdir -p viktor/dir with spaces/directory
#put some css files in that directory
$ touch viktor/dir with spaces/directory/a.css
$ touch viktor/dir with spaces/directory/b.css
$ touch viktor/dir with spaces/directory/c.css
# run Viktor's code, using the well-written instructions
$ /bin/bash ./script.sh 'victor/dir with spaces/directory' css
find: ‘viktor/dir’: No such file or directory
find: ‘spaces/directory’: No such file or directory
Note that I used ./script.sh
rather than plain script.sh
, because I had not set script.sh
to be executable. I can run it as Viktor shows if I first run
./script.sh
script.sh
script.sh
$ chmod +x script.sh
The problem comes from the way a bash
shell and the find
command handle spaces. With the first argument given simply as $1
, the spaces aren't treated a special way. That's probably not the best way to describe things. Perhaps a better way of explaining this concept is to show that bash
will assign the following.
bash
find
$1
bash
$0='script.sh'
$1='viktor/dir with spaces/directory'
$2='css'
This will happen even if we tell bash
that our directory has spaces
bash
$ /bin/bash script.sh viktor/dir with spaces/directory css
find: ‘viktor/dir’: No such file or directory
find: ‘spaces/directory’: No such file or directory
This can be seen by adding the lines, echo "$0 is $0"
, echo "$1 is $1"
, echo "$2 is $2"
, and further with other lines having $(insert_number_here_but_no_parentheses)
, if you'd like.
echo "$0 is $0"
echo "$1 is $1"
echo "$2 is $2"
$(insert_number_here_but_no_parentheses)
So, how do we fix this problem? Let's look at the man page for find
find
$ man find
# (press 'q' to get out of the display of the man page)
Okay, that was kind of scary.
Let's cut the original synopsis line down to
find [starting-point...] [expression]
What the DESCRIPTON means in its 'starting-point' explanation is that [starting-point...]
is a directory (or directories) from which you'll start your search. For now, just take it at face value that 'expression' is something that restricts the search -- in your case, you look for only files and then further filter the results by specifying that they have a certain file-extension.
[starting-point...]
Let's get back to the find $1 -type f -name "*.$2"
command. The main point to know here is that the command as shown here will be expanded to
find $1 -type f -name "*.$2"
find viktor/dir with spaces/directory -type f -name "*.css"
The "space problem" is that it will be interpreted by find
and by the shell as follows
find
find victor/dir with spaces/directory -type f -name "*.css"
| | `--------------------'
| | /
| | | Another '[expression]' (2)
| | | -- Another '[starting-point]'
| | -- '[expression]' (1)
| -- '[starting-point]' (supposedly a directory)
-- Command name
Note that our '[expression]' (1)
and '[expression]' (2)
don't factor into what happens because the two '[starting-place]'
paths fail.
'[expression]' (1)
'[expression]' (2)
'[starting-place]'
What's now shown in Viktor's code
#!/bin/bash
#@filename viktor_script.sh
find "$1" -type f -name "*.$2"
Leads to
find "viktor/dir with spaces/directory" -type f -name "*.css"
`--' `--------------------------------' `-------------------'
| | /
| | valid '[expression]' to define
| | a "filter" for files outputted
| |
| -- '[starting-point]' (a real directory)
| bash knows to include the spaces because
-- command name of the quotation marks
Let's run it, first making sure it's executable
$ chmod +x viktor_script.sh
$ /bin/bash ./viktor_script.sh css
$ /bin/bash viktor_script.sh 'viktor/dir with spaces/directory' css
viktor/dir with spaces/directory/a.css
viktor/dir with spaces/directory/b.css
viktor/dir with spaces/directory/c.css
You are right. I updated my script to wrap the directory in double quotes so it takes space input correctly.
– Victor Wong
Sep 7 '18 at 4:27
This is a great answer, and it should be said that answers that build on other answers are very welcome on Stack Overflow; the CC license conditions explicitly allow it. There is no need to put any disclaimers about this in the post, nor to direct people how to vote.
– halfer
Sep 8 '18 at 19:57
Thanks @halfer for helping me to understand some of the meta stuff, and thanks for editing.
– bballdave025
Sep 11 '18 at 18:15
It doesn’t look like you are using arguments here.
You should replace extension and directory with $1 and $2 to use arguments 1 and 2.
Also, it looks like you forgot to close that quote... and the braces around the directory look wrong... I think you need quotes around the braces.
(Can’t test the result unfortunately at the minute, sorry).
Okay I have changed it to find "$1" -type f -name "*$2" but it doesnt print the files
– user10328066
Sep 6 '18 at 23:46
Try referring here, it’s similar but had a slightly more complex requirement. stackoverflow.com/a/25694217/857994. Maybe you need a -print?
– John Humphreys - w00te
Sep 6 '18 at 23:51
@JohnHumphreys-w00te
-print
is the default.– Barmar
Sep 7 '18 at 0:16
-print
@jsmith147 That should work, although I'd write
"*.$2"
, so it requires a .
before the extension.– Barmar
Sep 7 '18 at 0:17
"*.$2"
.
@jsmith147 Put
set -x
at the beginning of the script, so you can see the variable expansions.– Barmar
Sep 7 '18 at 0:18
set -x
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
You have an unmatched quote. What is the
*
at the end for?– Barmar
Sep 7 '18 at 0:13