I spent too long on this
One of the best tools I’ve learned here at Flatiron School for how to solve coding problems is how to take advantage of console output and debugging tools to learn about runtime state. And yet, when I got back into shell scripting, I had to stop and get myself out of old, bad habits.
Today, I was already annoyed and upset for Reasons, and I was finally done with the entire concept of having to tab through cluttered directories. At Flatiron, and probably many other places, we’re constantly having to clone down git
repositories and even if you separate the related repositories into their own directories, you end up with many directories with similar names. I just want to easily cd
into the most recently created directory!
I knew from previous observation that chaining with |
and substitution with ${}
or ` was not going to work the way I wanted it to, but today I had or rather made, uh, distracted with spent an hour looking over some manpages. I had seen this before with some other scripts I had tried to write back in the day but lacked context to understand what I truly needed to do.
My understanding is as follows: at the command line you have a single shell process. When you chain or substitute, you fork a child shell process (a subshell) which completes a task and sends its return value or result from its stdout
to your active shell’s stdin
where you can see it. But there’s not a ton of latitude that subshells have to affect your active shell’s state.*
I tried a ton of variations on cd $( ${ls -t | head -1} )
which will get you a (bad substitution
) error, trying to figure out why this command didn’t work from a script but did work from the shell: cd $( `ls -t | head -1` ).
And until I echo
ed the pwd
at the end of the script, I didn’t realize that the script did work – it was changing the directory of the subshell that the script called on path was running in.
I really did feel quite silly, because you think you know about subshells and will remember but then in all the moments leading up to then I had not remembered and was suffering dearly for it.
The solution is to source
or import the script’s function to my current shell.
I added the following to my shell’s rc
file (~/.zshrc
because Apple’s nag was effective)
#custom sources
#cdnew
source $HOME/source/cdnew
And I made a source
directory that will be separate from my custom script’s bin
directory.
The file referenced from my rc
file contains this function:
~/source/cdnew
#source this file
cdnew() {
NEWESTDIR=`ls -t | head -1`
cd $NEWESTDIR
}
Now whenever I want to change into the newest created directory, I can just do that. And it’s way easier than tab-completing through several similarly named directories.
*This is a good thing, because it follows scoping conventions. Global shell variables are available to all of a user’s shells, local shell variables are known only to the shell or subshell running a function.
Reference: Bash FAQ