43

I want to write a shell script that will loop through all the files in a directory and echo "put ${filename}". Can anyone point me in the right direction?

codeforester
  • 39,467
  • 16
  • 112
  • 140
skline
  • 605
  • 1
  • 6
  • 8
  • 2
    What have you tried? What part of the `for` statement and the `*` operator confuse you? Can you be more specific about what you know and what you don't know about the shell? – S.Lott Dec 14 '11 at 22:15
  • Just came across this -- a warning to anyone using this as a reference -- the answers do not handle filenames with spaces properly... refer to https://stackoverflow.com/questions/7039130/iterate-over-list-of-files-with-spaces for a better solution!!! – blackghost Jun 02 '17 at 15:59

6 Answers6

65

For files and directories, not recursive

for filename in *; do echo "put ${filename}"; done

For files only (excludes folders), not recursive

for file in *; do 
    if [ -f "$file" ]; then 
        echo "$file" 
    fi 
done

For a recursive solution, see Bennet Yee's answer.

ThisClark
  • 14,352
  • 10
  • 69
  • 100
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 1
    If the current directory happens to be empty, this outputs "put *" rather than correctly outputting nothing. Can it be fixed? – JWWalker Apr 27 '13 at 01:47
  • 1
    @ThisClark - Indeed it does. But I'm not sure that an answer not doing *exactly* what you want is a good reason to downvote. – Oliver Charlesworth Sep 03 '18 at 16:52
  • @ThisClark - True. But being generous to myself (!), one could argue that from a *nix perspective, a folder **is** is a file. (Possibly that's what I was thinking when I wrote the answer 7 years ago, but who knows...) – Oliver Charlesworth Sep 03 '18 at 17:07
  • What does nix even stand for? Disregarding the distinction of files from folders is not helpful. – ThisClark Sep 03 '18 at 17:38
  • @ThisClark *nix meaning unix, linux, etc. – leetbacoon Dec 23 '19 at 00:51
  • This does not list any hidden files (i.e. those starting with ".") in bash on macOS 10.13. Is that normal? How do I get all files, including the hidden ones? – Thomas Tempelmann Apr 06 '20 at 16:00
  • 1
    @ThomasTempelmann try running 'shopt -s dotglob' right before. – Pedro A Mar 11 '22 at 03:27
  • What if one wants to pass the name of the directory as a variable (I posted a more precise question there: https://stackoverflow.com/questions/76021261/passing-a-string-to-a-loop-to-iterate-in-all-subdirectories-and-files) – ecjb Apr 15 '23 at 09:06
19

Recursively (including files in subdirectories)

find YOUR_DIR -type f -exec echo "put {}" \;

Non-recursively (only files in that directory)

find YOUR_DIR -maxdepth 1 -type f -exec echo "put {}" \;

Use * instead of YOUR_DIR to search the current directory

winklerrr
  • 13,026
  • 8
  • 71
  • 88
Bennet Yee
  • 506
  • 2
  • 6
  • 1
    I get the error `find 'dir': No such file or directory` when trying this. – gbmhunter Dec 19 '13 at 22:44
  • 2
    Silly me, by dir you meant replace with the directory you want. Still, slightly confusing! – gbmhunter Dec 19 '13 at 22:45
  • 1
    Recursively for files in the current directory, replace `dir` with `*`. – ThisClark Sep 03 '18 at 17:45
  • 2
    What does this part do? "put {}" Especially meaning of the curly braces {} – Ayusman Jul 03 '19 at 06:25
  • use '.' for all files in the current directory instead of 'dir'. note that find will also go through the "hidden" files/directories the names of which start with a dot. – Bennet Yee Feb 18 '21 at 23:05
  • the '{}' is replaced with the path to the filesystem object identified by the conditions specified earlier. – Bennet Yee Feb 18 '21 at 23:06
  • wouldn't a pipe with `$1` be easier than the ` -exec echo .. {} `? Also, I just noticed that find isn't GNU compliant with it's options syntax. Is it not a core util? Sorry for digging up this grandad of a Q / A, but it is a popular page, and I felt that I had useful info to add (the first part, not the second. ). – Nate T Aug 21 '21 at 01:59
8

For all folders and files in the current directory

for file in *; do
    echo "put $file"
done

Or, if you want to include subdirectories and files only:

find . -type f -exec echo put {} \;

If you want to include the folders themselves, take out the -type f part.

ThisClark
  • 14,352
  • 10
  • 69
  • 100
Kevin
  • 53,822
  • 15
  • 101
  • 132
3

If you don't have any files, then instead of printing * we can do this.

format=*.txt
for i in $format;
do
 if [[ "$i" == "$format" ]]
 then
    echo "No Files"
 else
    echo "file name $i"
 fi
done
Mad-D
  • 4,479
  • 18
  • 52
  • 93
1

One more alternative using ls and sed:

$ ls -1 <dir> | sed -e 's/^/put /'

and using ls and xargs:

$ ls -1 <dir> | xargs -n1 -i%f echo 'put %f'
jcollado
  • 39,419
  • 8
  • 102
  • 133
  • +1, but -1 is not needed and you can do sed -e 's/^/put /' – William Pursell Dec 15 '11 at 01:12
  • @WilliamPursell Thanks, I've updated my response. Somehow, I misunderstood and made the braces and the dollar sign part of the solution. Also, I'ved another solution with `xargs` and `echo`, but the `sed` one is still more concise. – jcollado Dec 15 '11 at 06:05
0

this will work also recursively if you have any sub directories and files inside them:

find . -type f|awk -F"/" '{print "put ",$NF}'
Vijay
  • 65,327
  • 90
  • 227
  • 319