0

I'm trying to create the script that will simply do cd ../ times n, where n is whatever I pass to it, or 1 by default:

STEPS=${1:-1}
for i in $STEPS; do
    cd ..
done

It doesn't give me any errors and it does nothing..

  • I ran your code and it did correctly put me up a single directory. The ${1:-1} is evaluated as 1. – Matthias Aug 25 '16 at 16:07
  • So is it my computer then? :/ this is very strange.. Thanks! – Kernel.Panic Aug 25 '16 at 16:09
  • I ran the code directly from a shell. You should try to see if that works. From a script, it will only do the cd command within the script not in your shell where you execute the script I believe. – Matthias Aug 25 '16 at 16:10
  • Add debugging output, so you understand what/where is happening. I.e. `echo currDir=$PWD ; cd .. ; echo nowDir=$PWD` . Good luck. – shellter Aug 25 '16 at 16:12
  • The result should be either 1 or N (being a number I pass as a first argument). It evaluates correctly - meaning it sets 1 if I don't pass let's say 4 or 5. Then the for loop gets executed once, but it doesn't do `cd ..`. And yes, I want to create a sequence. So if `$STEPS` is 5, it should loop 5 times. – Kernel.Panic Aug 25 '16 at 16:18
  • you probably meant to do `STEPS={1..n}` – Matthias Aug 25 '16 at 16:20
  • Why do you expect `for i in 2` to run twice? It'll assign `2` to `i` and run the loop once, just as `for i in *` will run only once if you only have one file, even if that file's name is `2`. – Charles Duffy Aug 25 '16 at 16:28
  • I think you actually want a Bash *function* for this, if you want to invoke it in an interactive shell. – Toby Speight Aug 25 '16 at 16:58

3 Answers3

3

You should be able to source it to do what you wish, e.g.

. yourscript.sh 3

to change directory 3 times. (notice the dot before the yourscript.sh)

After you fix the script at least, e.g.

#!/bin/bash
STEPS=$1
for ((i=1; i<=$STEPS; i++)); do
  cd ..
done

Thanks @Charles Duffy for mentioning sourcing, and thanks @chepner for the fixed for loop.

Some info:

Shell scripts are run inside a subshell, and each subshell has its own concept of what the current directory is. The cd succeeds, but as soon as the subshell exits, you're back in the interactive shell and nothing ever changed there.

from here

Community
  • 1
  • 1
Matthias
  • 3,160
  • 2
  • 24
  • 38
  • I followed this, but if I just `echo` from within the for loop, it works. I can see the output `n` times. However `cd` still does not work. Btw, I'm using bash, because if I use `sh`, then it dumps an error - `Bad for loop variable`. – Kernel.Panic Aug 25 '16 at 16:48
  • sh is a common extension for bash executable files. Did you make it executable with `chmod +x yourscript.sh`? I just ran this on a MATE desktop on my debian, and it did indeed move me back the directories. – Matthias Aug 25 '16 at 16:52
  • what terminal are you using? – Matthias Aug 25 '16 at 16:53
  • yes, I used `chmod +x` and btw, I just ran `cd /home` without anything else in the code, and it doesn't work. It might be my terminal then. I am using `zsh` and wondering if it has something to do with it. – Kernel.Panic Aug 25 '16 at 16:54
  • are you making sure to source it and not run it? e.g. not `./script.sh 1` but instead `. script.sh 1`? – Matthias Aug 25 '16 at 16:55
  • I think it actually is my `zsh`, because I just ran your version again and it closed the terminal window completely. – Kernel.Panic Aug 25 '16 at 16:57
  • That is indeed strange. Because I was curious, I actually installed `zsh`, and it gives me the error `.: no such file or directory: script.sh` when I try to source the script. So yes you are right might very well be `zsh`. – Matthias Aug 25 '16 at 16:59
  • Yep, it is `zsh` problem definitely, because I just ran the same exact code on a normal terminal and it works! Thanks guys! I will probably accept this answer, as it has all the mentions of others' comments and if anyone stumbles upon this question, it would be much easier for them to find the answer. Thanks guys! – Kernel.Panic Aug 25 '16 at 17:04
  • if you didn't notice @chepner modified his answer and mentioned how you can do this with `zsh`. Good luck – Matthias Aug 25 '16 at 17:08
1

In bash, you generally don't want to generate a sequence of numbers to iterate over. Use the C-style for loop:

for ((i=1; i<=$STEPS; i++)); do
  cd ..
done

If this is in a file, you need to source it ( . ./cd-up) rather than executing it (sh ./cd-up or ./cd-up, etc).

If you are, in fact, using zsh, you can simply use the repeat construct:

repeat $STEPS do cd ..; done

or its shorter form for simple commands

repeat $STEPS cd ..
chepner
  • 497,756
  • 71
  • 530
  • 681
  • God dammit! :D OK, the for loop works now, but `cd` doesn't work. I'm guessing it can't change the directory like this.. this is pain. – Kernel.Panic Aug 25 '16 at 16:28
  • 3
    @Kernel.Panic, are you expecting your script to change the directory of its parent process (that is, the separate shell that's launching it)? Your code is fine, but you'll need to put it in-process with the shell whose directory you want to change. You can do that by putting it in a shell function, or *sourcing* in the script. – Charles Duffy Aug 25 '16 at 16:29
  • @Kernel.Panic I believe it can. Check to see if [my answer](http://stackoverflow.com/a/39150500/5272567) can't help. – Matthias Aug 25 '16 at 16:47
0

Assuming that $STEPS is always a single number, then your for loop will only run for one iteration. This is because the type of loop that you're using expects a list of words:

for name in word1 word2 word3; do
    # some stuff
done

This will run three times, assigning each value in the list to variable $name.

Using a C-style loop, you could do this:

steps=${1:-1}
for (( i = 0; i < steps; ++i )); do
    cd ..
done

Alternatively, in any POSIX shell you can use a while loop:

steps=${1:-1}
while [ $steps -gt 0 ]; do
    cd ..
    steps=$(( steps - 1 ))
done

If you pass in something that's not an integer, then neither of these approaches will work!


Remember that if you run this as a script, it will change the directory while the script is running but the parent shell (the one you ran the script from) will be unaffected.

Tom Fenech
  • 72,334
  • 12
  • 107
  • 141