4

I would like to declare a few shortcut commands to switch between my various coding projects, so I have come up with the following script.

projects=$(ls -d ~/Workspace/*/)
prefix="/Users/myuser/Workspace/"
for f in $projects
do
        temp=${f#$prefix}
        temp=${temp/%\//}
        c="alias $temp='cd $f'"
        echo $c
        eval $c
done

I put that in a file called .workspace-shotcuts.sh in my homefolder, then I chmod +X .workspace-shotcuts.sh it. when I run it, using ./.workspace-shotcuts.sh I get

alias project1='cd /Users/myuser/Workspace/project1/'
alias project2='cd /Users/myuser/Workspace/project2/'

in the console. But the aliases are not declare (zsh: command not found: project1).

Also at the end of my .zshrc file I have added /bin/sh .workspace-shotcuts.sh, which gives the same output, but still no aliases.

Any body can tell me what I am missing? I would like to point out that I am not a great *nix user, so you might have to ELI5 some things to me.

EDIT:

I was suggested to use source instead, which I have done, but here is the error messages I get:

(eval):2: permission denied: /Users/myuser/Workspace/project1/
(eval):3: permission denied: /Users/myuser/Workspace/project2/    
(eval):4: permission denied: /Users/myuser/Workspace/project3/
(eval):5: permission denied: /Users/myuser/Workspace/project4/
(eval):6: permission denied: /Users/myuser/Workspace/project5/
(eval):7: permission denied: /Users/myuser/Workspace/project6/
(eval):8: permission denied: /Users/myuser/Workspace/project7/
(eval):9: no such file or directory: /Users/myuser/Workspace/project1=cd /Users/myuser/Workspace/project1/\n/Users/myuser/Workspace/project2/\n/Users/myuser/Workspace/project3/\n/Users/myuser/Workspace/project4/\n/Users/myuser/Workspace/project5/\n/Users/myuser/Workspace/project6/\n/Users/myuser/Workspace/project7/

What is happening? Is there some special permission I need to give my script?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
le-doude
  • 143
  • 1
  • 6
  • I think the problem may be that variables set or exported in a script cannot alter the calling (parent) environment. See http://stackoverflow.com/questions/8604462/setting-environment-variable-in-shell-script-does-not-make-it-visible-to-the-she for example. – msw Dec 13 '15 at 02:56
  • @Michael Homer, @cuonglm, @msw ... I have tried `source`, I do not think it fixed much. – le-doude Dec 13 '15 at 06:07
  • I don't know `zsh`, but it looks like you're having a problem with a difference between `zsh` and `/bin/sh`.  Try running `zsh .workspace-shotcuts.sh`; it will probably fail the same as the `source` command.  Then look at `zsh` documentation to figure out what you need to change to get it to work in `zsh`.  Then `source .workspace-shotcuts.sh` should work. – G-Man Says 'Reinstate Monica' Dec 13 '15 at 08:13

1 Answers1

8

One of your problems is that you executed your snippet in a separate shell process, which has no effect on the parent shell. It's the same problem as in How can I make environment variables "exported" in a shell script stick around?. You need to use the source builtin (also avilable under the name .) to execute the script inside the same shell.

source ~/.workspace-shotcuts.sh

Another problem is that you're trying to parse the output of ls. Don't do that. In shells such as sh and bash, you can get away with it because writing $projects outside of quotes splits the value at the newlines that separates the file names. Except that it doesn't actually work: for example, if the file names contain spaces, they will be broken into space-separated pieces. In a shell script, don't parse the output of ls, use wildcards instead. This is rather straightforward in zsh.

projects=(~/Workspace/*/)
for f in $projects; do …

What you're doing next is rather convoluted. You don't need eval here; using it only sets you up for quoting mishaps. Since you're using zsh, you can use the history modifier t to extract the last component of a path, without reaching for string manipulation constructs: $f:t. In case the file name contains special characters, you should protect them, and again zsh makes this easy thanks to the parameter expansion flag q: ${(q)f} gives you a quoted filename that you can use in the alias definition.

projects=(~/Workspace/*/)
for f in $projects
do
  alias $f:t="cd ${(q)f}"
done

But in fact, you're just reinventing cdpath plus auto_cd. Scratch all that and use

setopt auto_cd
cdpath+=~/Workspace

The auto_cd option lets you type a directory name to change into it, without having to type cd ‍ before it. The cdpath is an array of directory prefixes that cd foo tries if there isn't a subdirectory called foo in the current directory.


In case bash users see this thread: the alias method would be

projects=(~/Workspace/*/)
for f in "${projects[@]}"; do
  f=${f%/}
  alias ${f##*/}="cd '${f//\'/\'\\\'\'}'"
done

and the CDPATH method would be

CDPATH=$CDPATH:$HOME/Workspace
shopt -s autocd
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175