5

I wrote a new text file in /bin named ram which contains:

watch -n 1 free -h

and a file sen:

watch -n 1 sensors

in the same folder, in order to avoid typing

watch blahblahblah...

every time.

Also, I changed permissions of these two from

-rw-r--r--

to

-rw-r--r-x

and achieved my goal. It worked even after reopening shell, i.e. then I could type ram instead of watch -n 1 free -h

But, problem was encountered after I tried the same procedure for

cd /home/myname/Downloads/

and new text file saved in /bin and named dow, same with permissions.

This time dow does nothing in terminal, even not showing any message.

I tried saving the same file in /usr/bin, but again terminal does nothing and my working directory doesn't change.

How is this possible?

Zanna
  • 69,223
  • 56
  • 216
  • 327
mk1024
  • 659
  • 3
  • 11
  • 25

2 Answers2

7

You have written a script, and it works. It just doesn't do what you want, because a script runs in a separate shell from the shell that calls it.

The shell that the script runs in does exactly what the script tells it to; it changes its working directory to ~/Downloads. There is nothing else for it to do, so it exits. The calling shell's directory hasn't been changed.

You don't have to take my word for it - you can demonstrate it by adding ls on the next line of your dow file. The contents of your ~/Downloads directory (assuming it has some) will then be listed when you run the command (without the usual colours, which are provided by an alias in your ~/.bashrc that non-interactive shells don't read).

To execute a script in the current shell, you can use the source command, which can also be written as . file. So, if you type

. dow

Your current shell will change directory.

Or, you can instead set an alias:

zanna@toaster:~$ alias dow='cd $HOME/Downloads'
zanna@toaster:~$ dow
zanna@toaster:~/Downloads$ 

To make it permanent, add the line

alias dow='cd $HOME/Downloads'

to your ~/.bashrc file. It will then be available every time you run an interactive shell.

Zanna
  • 69,223
  • 56
  • 216
  • 327
  • 1
    Worth adding that an `alias` is probably a better approach for for the `watch` commands too. – Boris the Spider Mar 24 '18 at 09:51
  • @BoristheSpider agreed, but could you give a solid justification? I was tempted to add "and why are you putting your own programs here instead of `~/bin` or `/usr/local/bin`?", but I don't have any justification besides convention and PATH precedence... – Zanna Mar 24 '18 at 11:25
  • Convention is a powerful reason. Further, allowing unpriviledged users of the system to dump random executables into `/bin` is rather ... dangerous. `~/bin` would be a better choice, in which case how a user handles _their_ environment is their own choice. – Boris the Spider Mar 24 '18 at 11:28
3

This is a cross-site duplicate: https://stackoverflow.com/a/255415/383694.

The issue is that the script is run in a subshell. The script changes directory and then closes, making no change to your current shell.

Two mitigations:

  1. execute . dow to make the script run in the context of the current shell.
  2. use an alias, eg in your ~/.bashrc file that does the directory change - eg alias dow="cd /home/myname/Downloads/".

If you're changing directory it's usually a good idea to test that it worked before doing other things.

There are some other options in the linked question.

pbhj
  • 3,152
  • 21
  • 38