I was toying with the idea of creating an alias that would allow me to list the contents of a target subdirectory, without changing to that directory.
I have successfully been able to create both an alias and a script to change directory and display contents. I call the script leap and it is simply:
#!/bin/bash
PATH=/bin:/usr/bin:.
# script to change to a directory, then display current contents
cd $1 && ls -l -a
The alias I use to trigger leap is defined: alias lp='. ~/scripts/leap'
My hope was I could simply create an alias named pk (pk is for peek) and concatenate my leap script and a standard bash command using &&
. I could not be more wrong.
For reference, here is the contents of my current home directory (my user id has been replaced with $$$$):
drwxr-xr-x 3 $$$$$$ 46374 23 Aug 30 11:40 Fall_2019
drwxr-xr-x 5 $$$$$$ 46374 66 Aug 28 09:01 PAST_COURSES
drwxr-xr-x 3 $$$$$$ 46374 22 Aug 30 12:03 repos
drwxr-xr-x 3 $$$$$$ students 117 Aug 31 09:06 scripts
Using alias pk='lp $1 && cd ..'
Entering [$$$$@host ~]$ pk PAST_COURSES
results in:
-rw------- 1 $$$$$$ students 1766 Feb 28 2018 ~
drwx------ 10 $$$$$$ students 4096 Aug 31 09:06 .
drwx--x--x 1232 root root 28672 Aug 30 16:03 ..
-rw------- 1 $$$$$$ students 11368 Aug 30 12:20 .bash_history
-rw------- 1 $$$$$$ students 18 Aug 21 2017 .bash_logout
-rw------- 1 $$$$$$ students 180 Mar 8 2018 .bash_profile
-rw------- 1 $$$$$$ students 526 Aug 30 11:19 .bashrc
-rw------- 1 $$$$$$ students 266 Aug 21 2017 .cshrc
drwxr-xr-x 3 $$$$$$ 46374 23 Aug 30 11:40 Fall_2019
drwxr-xr-x 8 $$$$$$ students 155 Aug 30 12:14 .git
-rw-r--r-- 1 $$$$$$ students 87 Apr 11 2018 .gitconfig
-rw-r--r-- 1 $$$$$$ students 12288 Jan 29 2018 .hello.swp
-rw------- 1 $$$$$$ students 172 Aug 21 2017 .kshrc
-rw------- 1 $$$$$$ students 189 Mar 13 2018 .lesshst
-rw-r--r-- 1 $$$$$$ students 20480 Jan 29 2018 .ls.swn
drwxr-xr-x 5 $$$$$$ 46374 66 Aug 28 09:01 PAST_COURSES
drwxr----- 3 $$$$$$ 46374 18 Aug 30 12:16 .pki
drwxr-xr-x 3 $$$$$$ 46374 22 Aug 30 12:03 repos
drwxr-xr-x 3 $$$$$$ students 117 Aug 31 09:06 scripts
drwx------ 3 $$$$$$ students 103 Aug 30 11:12 .ssh
-rw------- 1 $$$$$$ students 12288 Sep 6 2017 .swp
drwxr-xr-x 2 $$$$$$ 46374 23 Aug 31 09:06 .vim
-rw-r--r-- 1 $$$$$$ students 8129 Aug 31 09:06 .viminfo
-rw-r--r-- 1 $$$$$$ students 142 Feb 14 2018 .vimrc
[$$$$@host home]$
As you can see, this displays the current directory ( ~ ) rather than switching to PAST_COURSES and displaying it. Additionally, the alias jumps up one directory above the current directory ( ~ ) rather than returning to it from PAST_COURSES.
Incidentally, I also get this exact result when I try using the following aliases:
pk='. ~/scripts/leap $1 && cd ..'
(using the script for leap rather than the alias)
pk='cd $1 && ls -l -a && cd ..'
(using the exact code inside leap )
In my tinkering I have noticed a few things:
First, if I simply type $$$$@host ~]$ ~/scripts/leap *[dir-name]*
I actually get EXACTLY what I want - a look into a directory without changing to it. All by omitting the leading .
, which boggles me.
Second, I can fix the current pk alias by changing the trailing cd ..
to cd $(pwd)
, though it will not display the target directory instead of the current one.
At this point, I'd like a little help - not just in a script or alias that will do the job. An explanation that explains this behavior that I'm seeing would be marvelous.
.
(the source builtin)alias pk='. ~/scripts/leap $1 && cd ..' (using the script for leap rather than the alias)
is not equivalent to
alias pk='cd $1 && ls -l -a && cd ..'
In the first one, the .
builtin (also known as source
) is used, while in the second it is not. .
doesn't just execute a command, it executes it in the current shell context. From the documentation:
. (a period)
. filename [arguments]
Read and execute commands from the filename argument in the current shell context.
That means anything the script does effects your current shell context. If the script changes directories, so does your current context.
If, on the other hand, the first version omitted the .
like this:
alias pk='~/scripts/leap $1 && cd ..'
then the contents of the leap
script would run in it's own bash context, but your current context would move up one directory (since the cd ..
isn't inside the leap script).
You could implement pk
using a function like this:
pk() {
pushd $1
if [[ $? == 0 ]]; then
# Successfully changed directories.
# Run command
$2
# Return from the pre-pushd directory.
popd
fi
}
From the Bash Manual | 6.6 Aliases:
For almost every purpose, shell functions are preferred over aliases.
alias foo="echo bar"
foo() {
echo bar
}