How to get the list of files in a directory in a shell script?
Solution 1
search_dir=/the/path/to/base/dir/
for entry in "$search_dir"/*
do
echo "$entry"
done
Solution 2
This is a way to do it where the syntax is simpler for me to understand:
yourfilenames=`ls ./*.txt`
for eachfile in $yourfilenames
do
echo $eachfile
done
./
is the current working directory but could be replaced with any path
*.txt
returns anything.txt
You can check what will be listed easily by typing the ls
command straight into the terminal.
Basically, you create a variable yourfilenames
containing everything the list command returns as a separate element, and then you loop through it. The loop creates a temporary variable eachfile
that contains a single element of the variable it's looping through, in this case a filename. This isn't necessarily better than the other answers, but I find it intuitive because I'm already familiar with the ls
command and the for loop syntax.
Solution 3
The other answers on here are great and answer your question, but this is the top google result for "bash get list of files in directory", (which I was looking for to save a list of files) so I thought I would post an answer to that problem:
ls $search_path > filename.txt
If you want only a certain type (e.g. any .txt files):
ls $search_path | grep *.txt > filename.txt
Note that $search_path is optional; ls > filename.txt will do the current directory.
Solution 4
for entry in "$search_dir"/* "$work_dir"/*
do
if [ -f "$entry" ];then
echo "$entry"
fi
done
Solution 5
$ pwd; ls -l
/home/victoria/test
total 12
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:31 a
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:31 b
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:31 c
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:32 'c d'
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:31 d
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32 dir_a
drwxr-xr-x 2 victoria victoria 4096 Apr 23 11:32 dir_b
-rw-r--r-- 1 victoria victoria 0 Apr 23 11:32 'e; f'
$ find . -type f
./c
./b
./a
./d
./c d
./e; f
$ find . -type f | sed 's/^\.\///g' | sort
a
b
c
c d
d
e; f
$ find . -type f | sed 's/^\.\///g' | sort > tmp
$ cat tmp
a
b
c
c d
d
e; f
Variations
$ pwd
/home/victoria
$ find $(pwd) -maxdepth 1 -type f -not -path '*/\.*' | sort
/home/victoria/new
/home/victoria/new1
/home/victoria/new2
/home/victoria/new3
/home/victoria/new3.md
/home/victoria/new.md
/home/victoria/package.json
/home/victoria/Untitled Document 1
/home/victoria/Untitled Document 2
$ find . -maxdepth 1 -type f -not -path '*/\.*' | sed 's/^\.\///g' | sort
new
new1
new2
new3
new3.md
new.md
package.json
Untitled Document 1
Untitled Document 2
Notes:
.
: current folder- remove
-maxdepth 1
to search recursively -type f
: find files, not directories (d
)-not -path '*/\.*'
: do not return.hidden_files
sed 's/^\.\///g'
: remove the prepended./
from the result list
Related videos on Youtube
jrharshath
Updated on March 05, 2022Comments
-
jrharshath over 2 years
I'm trying to get the contents of a directory using shell script.
My script is:
for entry in `ls $search_dir`; do echo $entry done
where
$search_dir
is a relative path. However,$search_dir
contains many files with whitespaces in their names. In that case, this script does not run as expected.I know I could use
for entry in *
, but that would only work for my current directory.I know I can change to that directory, use
for entry in *
then change back, but my particular situation prevents me from doing that.I have two relative paths
$search_dir
and$work_dir
, and I have to work on both simultaneously, reading them creating/deleting files in them etc.So what do I do now?
PS: I use bash.
-
drkg4b over 8 yearsI know this is pretty old but I can't seem to get the last
xargs -0 -i echo "{}"
command, care to explain me a bit? In particular what is the-i echo "{}"
part do? Also I read from theman
page that-i
is deprecated now and we should use-I
insted. -
Noel Yap over 8 years
-i
substitutes{}
with the arg. -
drkg4b over 8 yearsThanks! This is useful, also for the slow minded like me I think that the
{}
is the string that is replaced with the matches by thefind
command. -
Noel Yap over 8 yearsIt's what's replaced by
xargs
, notfind
. -
Noel Yap over 8 yearsI've updated the answer to use
-I
. Thanks for the heads up about the deprecation of-i
. -
gniourf_gniourf over 8 yearswhy do you use
xargs
? by default,find
prints what it finds... you could delete everything from-print0
. -
mrgloom over 8 yearsCan you explain why
for entry in "$search_dir/*"
don't work? Why we need to place/*
outside of quotes? -
Ignacio Vazquez-Abrams over 8 years@mrgloom: Because you need to let the shell glob the wildcard.
-
Alexej Magura over 7 yearswouldn't
find
be faster? -
Ignacio Vazquez-Abrams over 7 years@AlexejMagura:
find
is a separate process. Globbing happens in the shell. -
Victor Zamanian about 7 yearsNo need to use grep to get only .txt files: `ls $search_path/*.txt > filename.txt'. But more importantly, one should not use the output of the ls command to parse file names.
-
ThatsRightJack almost 7 yearsThe solution gives the full path. What if I just wanted to list what was in the current directory?
-
Ignacio Vazquez-Abrams almost 7 yearsJust omit the path.
-
funilrys almost 7 years@mrgloom if you want to do so you can achieve that with
for entry in "${search_dir}/*"
-
CallMeLoki over 6 yearsit doesn't work if a file is space seprated(consider each as an entry)
-
Agile Bean about 6 yearson MacOs, you don't need the parentheses - just write: for entry in ~/gcloud_installs/*
-
Soren Bjornstad almost 6 yearsThis works OK for a quick, informal script or one-liner, but it will break if a filename contains newlines, unlike the glob-based solutions.
-
rrr almost 6 years@SorenBjornstad thanks for the advice! I didn't know newlines were permitted in filenames- what kind of files might have them? Like, is this something that occurs commonly?
-
Soren Bjornstad almost 6 yearsNewlines in filenames are evil for this reason and as far as I know there's no legitimate reason to use them. I've never seen one in the wild myself. That said, it's totally possible to maliciously construct filenames with newlines in such a way as to exploit this. (For instance, imagine a directory containing files
A
,B
, andC
. You create files calledB\nC
andD
, then choose to delete them. Software that doesn't handle this right could end up deleting preexisting files B and C instead even if you didn't have permission to do that.) -
Noel Yap almost 6 yearsDoing that wouldn't handle file entries with spaces well.
-
samurai_jane over 5 years@VictorZamanian, can you elaborate why we should not use the output of
ls
to parse filenames? Haven't heard of this before. -
Victor Zamanian over 5 years@samurai_jane There's a lot of links to provide regarding this topic, but here's one first search result: mywiki.wooledge.org/ParsingLs. I even saw a question here on SO claiming the reasons for not parsing the output of ls were BS and was very elaborative about it. But the replies/answers still claimed it was a bad idea. Have a look: unix.stackexchange.com/questions/128985/…
-
Dmitry Gonchar about 5 yearsThis does not work recursively. For a recursive solution
find
is better. See this answer stackoverflow.com/a/55817578/1343917 -
Martin Jambon almost 4 yearsThis doesn't work (in bash with the default settings) if the folder is empty or if some files start with a period.
-
Georodin almost 4 yearsIs there a way to implement the
| grep *.txt
from the answer below to this snippet? -
tripleee over 3 years@Georodin Just use
"$search_dir"/*.txt
if that's what you want. -
tripleee over 3 years
for [ z
is a syntax error.if [ test
is silly and wrong. Not quoting"$z"
is a quoting error. -
tripleee over 3 yearsmywiki.wooledge.org/ParsingLs explains a large number of pitfalls with this approach. You should basically never use
ls
in scripts. It's silly anyway; the shell has already expanded the wildcard by the timels
runs. -
Inian over 3 years@Anish B: Stop vandalizing the original post. The answer was right as it is written
-
Inian over 3 years@AnishB.: No the answer as it was written should work fine for a directory name assigned to
search_dir
variable -
Inian over 3 years@AnishB.: If you have a problem using the attempt, then something is not right at your end. Suggest asking a new question to resolve it, instead of modifying a highly rated answer incorrectly (Also check if your
*
is outside of double quotes) -
Inian over 3 yearsThere is nothing wrong with the quoting of the
search_dir
variable. See When to wrap quotes around a shell variable?, i.e. to protect against directory names containing spaces -
Anish B. over 3 years@Inian I got the issue. Yes, you are right.
-
SnoopDogg over 3 yearsPlease explain. I successfully ran the code back when I wrote the answer. If you’re going to necropost at least be useful.
-
tripleee over 3 yearsWhat's to explain? If you tested this back then, you were definitely not using a standard shell. I already pointed out the errors, and it should not be hard to look up what the correct syntax looks like, from some of the other answers here even. But check out this demo: ideone.com/ERcu2c and fork it to your heart's content.
-
tripleee over 3 yearsIf you think this is irrelevant because it's old, you don't understand how Stack Overflow works. This is regularly - probably daily - linked as the canonical answer for new users who post duplicates of this common question, but also gets probably 100x that traffic from Google searches.
-
Admin almost 3 yearsAs it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
-
GG2 over 2 yearsIn addition to the comment by @MartinJambon, the "${search_dir}/*" doesn't seem to work at all for RedHat 7.9. If search_dir is empty (for any variation) or if using the latter variation, I confusingly get the contents of the current directory (assuming search_dir is not the current dir).
-
Nick Bull over 2 years@GG2 You may want to initially check that the variable is set correctly before proceeding:
if test -z "$search_dir"; then echo "No search directory provided"; exit 1; fi
-
GG2 over 2 years@NickBull I can't remember exactly how I was trying this originally. If I revisit this now, I don't get exactly the same results. If I let an empty string past, it lists contents of root. For an empty dir or containing only files starting with ".", it just echoes the evaluated value of "${search_dir}/*", e.g. empty_dir/*. It only lists the current directory if search_dir="." We'll chalk it up to something I did wrong.
-
Jeremy Caney over 2 yearsThere are eight existing answers to this question, including a top-voted, accepted answer with over three hundred votes. Are you certain your solution hasn't already been given? If not, why do you believe your approach improves upon the existing proposals, which have been validated by the community? Offering an explanation is always useful on Stack Overflow, but it's especially important where the question has been resolved to the satisfaction of both the OP and the community. Help readers out by explaining what your answer does different and when it might be preferred.
-
Gabriel Staples over 2 yearsHere are some other approaches I just added with
find
andls
where I capture the output into some bash arrays withmapfile
and then customize and print the contents of the arrays.