My final goal for this script is to:

  1. Visit folder in loop
  2. find the descriptor.mod
  3. Rename it to its folder name
  4. Relocate it to a specific folder
  5. repeat

Currently, when I am trying to visit the folder I get this error

$ . a.sh
bash: cd: 'a.sh/': No such file or directory
bash: cd: 'Folder 1/': No such file or directory
bash: cd: 'Folder 2/': No such file or directory
bash: cd: 'Folder 3/': No such file or directory
bash: cd: 'Folder 4/': No such file or directory
bash: cd: 'Folder 5/': No such file or directory
bash: cd: 'Folder 6/': No such file or directory

This is my code. There are six folders named Folder {number}

for f in *
    cd "'$f/'"
    echo "haha"
    cd ..

cd "E:\School\LINUX"

EDIT: Found it. I changed for f in * to for f in */

  • Strangely you don't get any error from cd "E:\School\LINUX". Is E:\School\LINUX a directory? Note in Linux this name is a single component, not a path with many components. – Kamil Maciorowski Jun 22 at 16:27

The command cd "'$f/'" contains outer double-quotes that will be removed by the shell after they serve they purpose of quoting. The inner single-quotes will survive and get to cd as parts of the argument. (More about quotes within quotes here: Parameter expansion (variable expansion) and quotes within quotes.)

In effect you're trying to cd to e.g. 'Folder 1/' with literal single-quotes, while the existing target is Folder 1/. There is no 'Folder 1/' directory.

Additionally * matches non-directories as well. a.sh is the script. After you add / and single-quotes, you're trying to cd to 'a.sh/'. There is no such directory.

Having failed to cd into this non-directoriy, you then subsequently also run cd .., which will take you out of the starting directory, and into its parent. From here, the entities that the original * matched are no longer visible, and so all further attempts to cd fail too... in fact, each subsequent failed cd will take you up one directory.

You need for f in */ to iterate over directories only (but note * doesn't match dotfiles). Then you don't need to add / because the trailing slash appears from the expansion of $f (although another trailing slash shouldn't break anything). And you absolutely shouldn't add single-quotes to the argument of cd. The relevant line should be cd "$f".

You could use a loop like the following to iterate through all entities, skipping non-directories, and handling cd errors correctly:

  • [ ! -d "${f}" ] && continue to skip non-directories (note: this will still match symlinks that point at directories)
  • cd "${f}" || continue to skip directories we can't enter (e.g: permissions)
  • pushd "${f}" / popd to avoid relative cd return attempts
for f in *; do
    # skip non-directories
    [ ! -d "$f" ] && continue

    # skip processing for directories we can't enter (e.g: permissions)
    pushd "$f" || continue

    echo "hi"

  • Not sure why this answer hasn't been excepted, it seems pretty comprehensive! – Bill Naylor Jul 14 at 21:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.