maddie
maddie

Reputation: 1954

Bash script: cd No such file or directory when file exists

My bash script is written to go to each subfolder in the current directory:

for d in */; 
do
    target=${d%/}
    cd "$target"
done

When I run my bash script, I am getting a cd error for a directory that exists:

++ for d in '*/'
++ target='Zelkova serrata'
++ cd 'Zelkova serrata'
./script7.sh: line 8: cd: Zelkova serrata: No such file or directory

Yet, in terminal command line I can do cd 'Zelkova serrata' within the same directory as the script and all is fine. Is it possible the bash script has a different source directory than the one its located in?

Upvotes: 0

Views: 9823

Answers (4)

Martin Kealey
Martin Kealey

Reputation: 697

To understand what's happening, try this and examine the output carefully:

mkdir -p A/B/C B C D

echo Trying sequence: */
pwd
for d in */ ; do
    cd "$d"
    pwd
done

Perhaps what you want is:

mkdir -p A/B/C B C D

exec 3<. ; orig_dir=/proc/$$/fd/3

echo Trying sequence: */
pwd
for d in */ ; do
    cd -P "$orig_dir/$d"
    pwd
done
cd -P "$orig_dir"
pwd

or if exec 3<. does not work in your shell:

mkdir -p A/B/C B C D

orig_dir=$PWD

echo Trying sequence: */
pwd
for d in */ ; do
    cd -P "$orig_dir/$d"
    pwd
done
cd -P "$orig_dir"
pwd

Upvotes: 0

Hellseher
Hellseher

Reputation: 286

With bullet proofing

~$ find /full/path/to/dir -maxdepth 1 -type d -printo | xargs -0 -I% sh -c "cd %; echo "do some fun here""

You'll escape name splitting if there is any space there.

Upvotes: 0

Paul
Paul

Reputation: 27473

The issue is that the current directory is "state" that is modified on each pass of the loop and to use the posted commands, the cwd state should not be changed by a pass.

Spawning a subshell can fix this problem of mutating state. The subshell inherits the state of its parent, but does not affect the parent.

do ( command; command ; ...; ) will spawn a new shell on each loop pass.

for d in */; 
do (
  target=${d%/}
  cd "$target"
) done

Upvotes: 2

MauricioRobayo
MauricioRobayo

Reputation: 2356

You are looping through relative paths, try including the absolute path, for example:

#!/bin/bash

pwd=$PWD
for d in */; 
do
    target="$pwd/${d%/}"
    cd "$target"
    echo $PWD
done

Upvotes: 3

Related Questions