Alias for cd in Linux csh - linux

I used to have an alias for cd in csh, which can show the current time and directory at the beginning of the cmdline and trigger the ls command.
The effect is like this:
[10:24] /home/cambridgelv/Desktop/cd ..
Desktop Documents Downloads Music
[10:24] /home/cambridgelv/cd Desktop
abc.doc def.jpg
[10:25] /home/cambridgelv/Desktop/
Does anybody have any idea?

Let me answer it by myself.
I thought maybe I aliased the set prompt command into cd before, so we can do this separately.
Refer to this answer: https://stackoverflow.com/a/33037878/11768989
You can customize the prompt in any way.
Mine is look like this:
set prompt = '%{\e[35;40;1m%}[%T #%m]%{\e[0m%} %~/'
alias cd "cd \!:1; ls"

The easiest would be to hook in to the special cwdcmd alias; this gets run every time the current directory changes.
alias cwdcmd 'printf "[%s] " `date +%H:%m`'
For example, where > is the prompt:
> sleep 1
> cd /
[14:06] > sleep 1
> cd ~
[14:06] >
You can also alias cd with something like:
alias cd 'cd $* && printf "[%s] " `date +%H:%m`'
Where $* expand to the command arguments /dir in cd /dir. However, this also prints the directory in square brackets for some reason that I don't quite understand. The cwdcmd alias is better anyway.

Related

Automate ls command after every cd command in tcsh

I change the directory by giving cd (dir_path). When I give this, it also wants to display the contents in the directory. Say like if we type ls after going to that directory. Basically the two commands should execute together cd (dir_path) and a ls in that path only by giving the cd (dir_path) command.
How to do that in tcsh?
According to uzsolt's comment this answer doesn't apply to tcsh. The original question did not name this requirement. The question was edited later after the OP mentioned tcsh in a comment.
See uzsolt's answer for a solution that works with tcsh. This answer should be upvoted.
In bash or zsh you can define a function named cd
cd ()
{
command cd "$#" && ls
}
When you then run cd somedir you will call your function cd instead of the command. If you want to call the normal cd command, use
command cd [somedir]
Or you can later remove the function using
unset cd
Or define a function of a different name and use an alias
cdls ()
{
command cd "$#" && ls
}
alias cd=cdls
You can then use cdls [somedir] or cd [somedir].
Again you can call
command cd [somedir]
to get the normal cd command.
You can also remove the alias to get the normal behavior.
unalias cd
I think the simpliest method is to use cwdcmd:
alias cwdcmd ls
Can be put it into ~/.tcshrc.
See man tcsh:
Special aliases
....
cwdcmd
Runs after every change of working directory.
alias cd 'cd \!* && ls && pwd'
There is a way to execute command one after another using && operator
cd `directory` && ls

Bash decorating "cd" - change directory inside a script [duplicate]

I'm trying to write a small script to change the current directory to my project directory:
#!/bin/bash
cd /home/tree/projects/java
I saved this file as proj, added execute permission with chmod, and copied it to /usr/bin. When I call it by:
proj, it does nothing. What am I doing wrong?
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.
One way to get around this is to use an alias instead:
alias proj="cd /home/tree/projects/java"
You're doing nothing wrong! You've changed the directory, but only within the subshell that runs the script.
You can run the script in your current process with the "dot" command:
. proj
But I'd prefer Greg's suggestion to use an alias in this simple case.
The cd in your script technically worked as it changed the directory of the shell that ran the script, but that was a separate process forked from your interactive shell.
A Posix-compatible way to solve this problem is to define a shell procedure rather than a shell-invoked command script.
jhome () {
cd /home/tree/projects/java
}
You can just type this in or put it in one of the various shell startup files.
The cd is done within the script's shell. When the script ends, that shell exits, and then you are left in the directory you were. "Source" the script, don't run it. Instead of:
./myscript.sh
do
. ./myscript.sh
(Notice the dot and space before the script name.)
To make a bash script that will cd to a select directory :
Create the script file
#!/bin/sh
# file : /scripts/cdjava
#
cd /home/askgelal/projects/java
Then create an alias in your startup file.
#!/bin/sh
# file /scripts/mastercode.sh
#
alias cdjava='. /scripts/cdjava'
I created a startup file where I dump all my aliases and custom functions.
Then I source this file into my .bashrc to have it set on each boot.
For example, create a master aliases/functions file: /scripts/mastercode.sh
(Put the alias in this file.)
Then at the end of your .bashrc file:
source /scripts/mastercode.sh
Now its easy to cd to your java directory, just type cdjava and you are there.
You can use . to execute a script in the current shell environment:
. script_name
or alternatively, its more readable but shell specific alias source:
source script_name
This avoids the subshell, and allows any variables or builtins (including cd) to affect the current shell instead.
Jeremy Ruten's idea of using a symlink triggered a thought that hasn't crossed any other answer. Use:
CDPATH=:$HOME/projects
The leading colon is important; it means that if there is a directory 'dir' in the current directory, then 'cd dir' will change to that, rather than hopping off somewhere else. With the value set as shown, you can do:
cd java
and, if there is no sub-directory called java in the current directory, then it will take you directly to $HOME/projects/java - no aliases, no scripts, no dubious execs or dot commands.
My $HOME is /Users/jleffler; my $CDPATH is:
:/Users/jleffler:/Users/jleffler/mail:/Users/jleffler/src:/Users/jleffler/src/perl:/Users/jleffler/src/sqltools:/Users/jleffler/lib:/Users/jleffler/doc:/Users/jleffler/work
Use exec bash at the end
A bash script operates on its current environment or on that of its
children, but never on its parent environment.
However, this question often gets asked because one wants to be left at a (new) bash prompt in a certain directory after execution of a bash script from within another directory.
If this is the case, simply execute a child bash instance at the end of the script:
#!/usr/bin/env bash
cd /home/tree/projects/java
echo -e '\nHit [Ctrl]+[D] to exit this child shell.'
exec bash
To return to the previous, parental bash instance, use Ctrl+D.
Update
At least with newer versions of bash, the exec on the last line is no longer required. Furthermore, the script could be made to work with whatever preferred shell by using the $SHELL environment variable. This then gives:
#!/usr/bin/env bash
cd desired/directory
echo -e '\nHit [Ctrl]+[D] to exit this child shell.'
$SHELL
I got my code to work by using. <your file name>
./<your file name> dose not work because it doesn't change your directory in the terminal it just changes the directory specific to that script.
Here is my program
#!/bin/bash
echo "Taking you to eclipse's workspace."
cd /Developer/Java/workspace
Here is my terminal
nova:~ Kael$
nova:~ Kael$ . workspace.sh
Taking you to eclipe's workspace.
nova:workspace Kael$
simply run:
cd /home/xxx/yyy && command_you_want
When you fire a shell script, it runs a new instance of that shell (/bin/bash). Thus, your script just fires up a shell, changes the directory and exits. Put another way, cd (and other such commands) within a shell script do not affect nor have access to the shell from which they were launched.
You can do following:
#!/bin/bash
cd /your/project/directory
# start another shell and replacing the current
exec /bin/bash
EDIT: This could be 'dotted' as well, to prevent creation of subsequent shells.
Example:
. ./previous_script (with or without the first line)
On my particular case i needed too many times to change for the same directory.
So on my .bashrc (I use ubuntu) i've added the
1 -
$ nano ~./bashrc
function switchp
{
cd /home/tree/projects/$1
}
2-
$ source ~/.bashrc
3 -
$ switchp java
Directly it will do: cd /home/tree/projects/java
Hope that helps!
It only changes the directory for the script itself, while your current directory stays the same.
You might want to use a symbolic link instead. It allows you to make a "shortcut" to a file or directory, so you'd only have to type something like cd my-project.
You can combine Adam & Greg's alias and dot approaches to make something that can be more dynamic—
alias project=". project"
Now running the project alias will execute the project script in the current shell as opposed to the subshell.
You can combine an alias and a script,
alias proj="cd \`/usr/bin/proj !*\`"
provided that the script echos the destination path. Note that those are backticks surrounding the script name.
For example, your script could be
#!/bin/bash
echo /home/askgelal/projects/java/$1
The advantage with this technique is that the script could take any number of command line parameters and emit different destinations calculated by possibly complex logic.
to navigate directories quicky, there's $CDPATH, cdargs, and ways to generate aliases automatically
http://jackndempsey.blogspot.com/2008/07/cdargs.html
http://muness.blogspot.com/2008/06/lazy-bash-cd-aliaes.html
https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5827311.html
In your ~/.bash_profile file. add the next function
move_me() {
cd ~/path/to/dest
}
Restart terminal and you can type
move_me
and you will be moved to the destination folder.
You can use the operator && :
cd myDirectory && ls
While sourcing the script you want to run is one solution, you should be aware that this script then can directly modify the environment of your current shell. Also it is not possible to pass arguments anymore.
Another way to do, is to implement your script as a function in bash.
function cdbm() {
cd whereever_you_want_to_go
echo "Arguments to the functions were $1, $2, ..."
}
This technique is used by autojump: http://github.com/joelthelion/autojump/wiki to provide you with learning shell directory bookmarks.
You can create a function like below in your .bash_profile and it will work smoothly.
The following function takes an optional parameter which is a project.
For example, you can just run
cdproj
or
cdproj project_name
Here is the function definition.
cdproj(){
dir=/Users/yourname/projects
if [ "$1" ]; then
cd "${dir}/${1}"
else
cd "${dir}"
fi
}
Dont forget to source your .bash_profile
This should do what you want. Change to the directory of interest (from within the script), and then spawn a new bash shell.
#!/bin/bash
# saved as mov_dir.sh
cd ~/mt/v3/rt_linux-rt-tools/
bash
If you run this, it will take you to the directory of interest and when you exit it it will bring you back to the original place.
root#intel-corei7-64:~# ./mov_dir.sh
root#intel-corei7-64:~/mt/v3/rt_linux-rt-tools# exit
root#intel-corei7-64:~#
This will even take you to back to your original directory when you exit (CTRL+d)
I did the following:
create a file called case
paste the following in the file:
#!/bin/sh
cd /home/"$1"
save it and then:
chmod +x case
I also created an alias in my .bashrc:
alias disk='cd /home/; . case'
now when I type:
case 12345
essentially I am typing:
cd /home/12345
You can type any folder after 'case':
case 12
case 15
case 17
which is like typing:
cd /home/12
cd /home/15
cd /home/17
respectively
In my case the path is much longer - these guys summed it up with the ~ info earlier.
As explained on the other answers, you have changed the directory, but only within the sub-shell that runs the script. this does not impact the parent shell.
One solution is to use bash functions instead of a bash script (sh); by placing your bash script code into a function. That makes the function available as a command and then, this will be executed without a child process and thus any cd command will impact the caller shell.
Bash functions :
One feature of the bash profile is to store custom functions that can be run in the terminal or in bash scripts the same way you run application/commands this also could be used as a shortcut for long commands.
To make your function efficient system widely you will need to copy your function at the end of several files
/home/user/.bashrc
/home/user/.bash_profile
/root/.bashrc
/root/.bash_profile
You can sudo kwrite /home/user/.bashrc /home/user/.bash_profile /root/.bashrc /root/.bash_profile to edit/create those files quickly
Howto :
Copy your bash script code inside a new function at the end of your bash's profile file and restart your terminal, you can then run cdd or whatever the function you wrote.
Script Example
Making shortcut to cd .. with cdd
cdd() {
cd ..
}
ls shortcut
ll() {
ls -l -h
}
ls shortcut
lll() {
ls -l -h -a
}
If you are using fish as your shell, the best solution is to create a function. As an example, given the original question, you could copy the 4 lines below and paste them into your fish command line:
function proj
cd /home/tree/projects/java
end
funcsave proj
This will create the function and save it for use later. If your project changes, just repeat the process using the new path.
If you prefer, you can manually add the function file by doing the following:
nano ~/.config/fish/functions/proj.fish
and enter the text:
function proj
cd /home/tree/projects/java
end
and finally press ctrl+x to exit and y followed by return to save your changes.
(NOTE: the first method of using funcsave creates the proj.fish file for you).
You need no script, only set the correct option and create an environment variable.
shopt -s cdable_vars
in your ~/.bashrc allows to cd to the content of environment variables.
Create such an environment variable:
export myjava="/home/tree/projects/java"
and you can use:
cd myjava
Other alternatives.
Note the discussion How do I set the working directory of the parent process?
It contains some hackish answers, e.g.
https://stackoverflow.com/a/2375174/755804 (changing the parent process directory via gdb, don't do this) and https://stackoverflow.com/a/51985735/755804 (the command tailcd that injects cd dirname to the input stream of the parent process; well, ideally it should be a part of bash rather than a hack)
It is an old question, but I am really surprised I don't see this trick here
Instead of using cd you can use
export PWD=the/path/you/want
No need to create subshells or use aliases.
Note that it is your responsibility to make sure the/path/you/want exists.
I have to work in tcsh, and I know this is not an elegant solution, but for example, if I had to change folders to a path where one word is different, the whole thing can be done in the alias
a alias_name 'set a = `pwd`; set b = `echo $a | replace "Trees" "Tests"` ; cd $b'
If the path is always fixed, the just
a alias_name2 'cd path/you/always/need'
should work
In the line above, the new folder path is set
This combines the answer by Serge with an unrelated answer by David. It changes the directory, and then instead of forcing a bash shell, it launches the user's default shell. It however requires both getent and /etc/passwd to detect the default shell.
#!/usr/bin/env bash
cd desired/directory
USER_SHELL=$(getent passwd <USER> | cut -d : -f 7)
$USER_SHELL
Of course this still has the same deficiency of creating a nested shell.

Infinite recursion aliasing `cd`

I want to record my most recent cd across any one of my terminals. I thought a good way to do this would be to write a simple bash script wrapping cd:
#!/bin/bash
cd $1 && echo `pwd` > /tmp/.cwd
Since I want the cd to occur in my terminal's process, I need to run the script with . bettercd.sh, correct?
Here comes my issue:
If I alias cd to this new . bettercd.sh, my shell also expands the cd inside of the script with the . bettercd.sh -- infinite recursion.
Is there any way to call cd from a different name but with the same behavior? To put it another way, is there some command that behaves exactly (or very similar to) cd that I can use in my shell script without noticing a difference when I use the aliased cd day to day?
My shell of choice is zsh, if that's relevant in some way.
Thanks for your help.
Since you are using zsh, you can use builtin cd in place of cd. This forces the shell to use the builtin command instead of recursively calling your alias.
builtin does not exist in standard bourne shell. If you need this to work in other shells, try prefixing cd with a backslash like this: \cd. It works to bypass aliases but not shell functions.
zsh provides the chpwd_functions hook functions specifically for tools like this. If you define a function to append the new directory to a file and add the function to the chpwd_functions array, it'll automatically run the routine every time it changed directory -- whether for pushd popd or cd:
$ record_pwd() { pwd > /tmp/cwd }
$ chpwd_functions=(record_pwd)
$ cd /tmp ; cat /tmp/cwd
/tmp
$ cd /etc ; cat /tmp/cwd
/etc
$
Inside your script call cd with builtin:
#!/bin/bash
builtin cd $1 && echo `pwd` > /tmp/.cwd
In addition to already posted answers (I personally would prefer #sarnold’s one) you can use the fact that chdir in zsh has the same behavior as cd, but is not an alias of the kind you can define with alias (it may be an “alias” in C source code, I do not know) thus using it is safe.
You could try putting unalias cd at the top of your bettercd.sh
I'd suggest a different name to avoid exactly this happening - what if some other script does a CD - if it uses your version instead of "normal", that could play havock with the system.

How do I execute an arbitrary script with a working directory of the directory its in?

I need to execute a groovy script file from bash, and I need the script to have a working directory of the directory it exists in.
That is, in my bash script, I'm doing this:
/opt/script/myscript.groovy &
But this seems to set the working directory to /etc/init.d, the directory I'm calling from. How do I change the working directory for that script to /opt/script?
If you are using start-stop-daemon inside your /etc/init.d script, you can take advantage of the -d parameter for achieving this:
-d, --chdir path
Chdir to path before starting the process. This is done after the chroot if the -r|--chroot option is set. When not specified, start-stop-daemon will chdir to the root directory before starting the process.
/etc/init.d
probably you are runnig (starting) that script from /etc/init.d?
Add cd /opt/script at the first line of the script
OR
...to keep it dynamic, add:
cd "$(dirname "$0")"
In bash putting that in the script works best:
HERE=$(cd -- $(dirname ${BASH_SOURCE[0]}) > /dev/null && pwd)
cd -- "$HERE"
This will succeed even with the following invocation (of /path/to/script.sh):
PATH="/path/to:$PATH" bash script.sh
where HERE=$(dirname $0) would fail.
Optionally you could also use pwd -P instead of just pwd, then $HERE will contain the realpath (canonicalized absolute pathname) as of man 3 realpath.
Something like this maybe:
SCRIPT=/opt/script/myscript.groovy
pushd `dirname $SCRIPT`
./`basename $SCRIPT`
popd

/bin/sh: pushd: not found

I am doing the following inside a make file
pushd %dir_name%
and i get the following error
/bin/sh : pushd : not found
Can someone please tell me why this error is showing up ?
I checked my $PATH variable and it contains /bin so I don't think that is causing a problem.
pushd is a bash enhancement to the POSIX-specified Bourne Shell. pushd cannot be easily implemented as a command, because the current working directory is a feature of a process that cannot be changed by child processes. (A hypothetical pushd command might do the chdir(2) call and then start a new shell, but ... it wouldn't be very usable.) pushd is a shell builtin, just like cd.
So, either change your script to start with #!/bin/bash or store the current working directory in a variable, do your work, then change back. Depends if you want a shell script that works on very reduced systems (say, a Debian build server) or if you're fine always requiring bash.
add
SHELL := /bin/bash
at the top of your makefile
I have found it on another question How can I use Bash syntax in Makefile targets?
A workaround for this would be to have a variable get the current working directory. Then you can cd out of it to do whatever, then when you need it, you can cd back in.
i.e.
oldpath=`pwd`
#do whatever your script does
...
...
...
# go back to the dir you wanted to pushd
cd $oldpath
sudo dpkg-reconfigure dash
Then select no.
This is because pushd is a builtin function in bash. So it is not related to the PATH variable and also it is not supported by /bin/sh (which is used by default by make. You can change that by setting SHELL (although it will not work directly (test1)).
You can instead run all the commands through bash -c "...". That will make the commands, including pushd/popd, run in a bash environment (test2).
SHELL = /bin/bash
test1:
#echo before
#pwd
#pushd /tmp
#echo in /tmp
#pwd
#popd
#echo after
#pwd
test2:
#/bin/bash -c "echo before;\
pwd; \
pushd /tmp; \
echo in /tmp; \
pwd; \
popd; \
echo after; \
pwd;"
When running make test1 and make test2 it gives the following:
prompt>make test1
before
/download/2011/03_mar
make: pushd: Command not found
make: *** [test1] Error 127
prompt>make test2
before
/download/2011/03_mar
/tmp /download/2011/03_mar
in /tmp
/tmp
/download/2011/03_mar
after
/download/2011/03_mar
prompt>
For test1, even though bash is used as a shell, each command/line in the rule is run by itself, so the pushd command is run in a different shell than the popd.
This ought to do the trick:
( cd dirname ; pwd ); pwd
The parentheses start a new child shell, thus the cd changes the directory within the child only, and any command after it within the parentheses will run in that folder. Once you exit the parentheses you are back in wherever you were before..
here is a method to point
sh -> bash
run this command on terminal
sudo dpkg-reconfigure dash
After this you should see
ls -l /bin/sh
point to /bin/bash (and not to /bin/dash)
Reference
Your shell (/bin/sh) is trying to find 'pushd'. But it can't find it because 'pushd','popd' and other commands like that are build in bash.
Launch you script using Bash (/bin/bash) instead of Sh like you are doing now, and it will work
Synthesizing from the other responses: pushd is bash-specific and you are make is using another POSIX shell. There is a simple workaround to use separate shell for the part that needs different directory, so just try changing it to:
test -z gen || mkdir -p gen \
&& ( cd $(CURRENT_DIRECTORY)/genscript > /dev/null \
&& perl genmakefile.pl \
&& mv Makefile ../gen/ ) \
&& echo "" > $(CURRENT_DIRECTORY)/gen/SvcGenLog
(I substituted the long path with a variable expansion. I probably is one in the makefile and it clearly expands to the current directory).
Since you are running it from make, I would probably replace the test with a make rule, too. Just
gen/SvcGenLog :
mkdir -p gen
cd genscript > /dev/null \
&& perl genmakefile.pl \
&& mv Makefile ../gen/ \
echo "" > gen/SvcGenLog
(dropped the current directory prefix; you were using relative path at some points anyway)
And than just make the rule depend on gen/SvcGenLog. It would be a bit more readable and you can make it depend on the genscript/genmakefile.pl too, so the Makefile in gen will be regenerated if you modify the script. Of course if anything else affects the content of the Makefile, you can make the rule depend on that too.
Note that each line executed by a make file is run in its own shell anyway. If you change directory, it won't affect subsequent lines. So you probably have little use for pushd and popd, your problem is more the opposite, that of getting the directory to stay changed for as long as you need it!
Run "apt install bash"
It will install everything you need and the command will work

Resources