Viewed   115 times

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

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.


for entry in "$search_dir"/*
  echo "$entry"
Tuesday, November 29, 2022

UPDATE 2017:

In C++17 there is now an official way to list files of your file system: std::filesystem. There is an excellent answer from Shreevardhan below with this source code:

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;

Old Answer:

In small and simple tasks I do not use boost, I use dirent.h. It is available as a standard header in UNIX, and also available for Windows via a compatibility layer created by Toni Ronkko.

DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\src\")) != NULL) {
  /* print all the files and directories within directory */
  while ((ent = readdir (dir)) != NULL) {
    printf ("%sn", ent->d_name);
  closedir (dir);
} else {
  /* could not open directory */
  perror ("");
  return EXIT_FAILURE;

It is just a small header file and does most of the simple stuff you need without using a big template-based approach like boost(no offence, I like boost!).

Friday, November 11, 2022

To check if a directory exists in a shell script, you can use the following:

if [ -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY exists.

Or to check if a directory doesn't exist:

if [ ! -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY doesn't exist.

However, as Jon Ericson points out, subsequent commands may not work as intended if you do not take into account that a symbolic link to a directory will also pass this check. E.g. running this:

if [ -d "$SYMLINK" ]; then 
  rmdir "$SYMLINK" 

Will produce the error message:

rmdir: failed to remove `symlink': Not a directory

So symbolic links may have to be treated differently, if subsequent commands expect directories:

if [ -d "$LINK_OR_DIR" ]; then 
  if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here.
    rm "$LINK_OR_DIR"
    # It's a directory!
    # Directory command goes here.
    rmdir "$LINK_OR_DIR"

Take particular note of the double-quotes used to wrap the variables. The reason for this is explained by 8jean in another answer.

If the variables contain spaces or other unusual characters it will probably cause the script to fail.

Sunday, September 4, 2022

The quotes are causing the error messages.

To get a count of files in the directory:

shopt -s nullglob

which creates an array and then replaces it with the count of its elements. This will include files and directories, but not dotfiles or . or .. or other dotted directories.

Use nullglob so an empty directory gives a count of 0 instead of 1.

You can instead use find -type f or you can count the directories and subtract:

# continuing from above
(( numfiles -= numdirs ))

Also see "How can I find the latest (newest, earliest, oldest) file in a directory?"

You can have as many spaces as you want inside an execution block. They often aid in readability. The only downside is that they make the file a little larger and may slow initial parsing (only) slightly. There are a few places that must have spaces (e.g. around [, [[, ], ]] and = in comparisons) and a few that must not (e.g. around = in an assignment.

Thursday, December 1, 2022

Use a shell function to front-end your script

setup () {
  # first, call your big script.
  # (It could be open-coded here but that might be a bit ugly.)

  # then finally...

  cd someplace

Put the shell function in a shell startup file.

Friday, August 26, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :