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.






You have an unmatched quote. What is the * at the end for?

– Barmar
Sep 7 '18 at 0:13


*




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.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)