View previous topic :: View next topic |
Author |
Message |
masinick Linux Guru

Joined: 03 Apr 2025 Posts: 8615 Location: Concord, NH
|
Posted: Thu Oct 11, 2025 1:16 am Post subject: Pushd, popd, and dirs in Bash |
|
|
I yanked these tidbits out of a Linux Journal Email newsletter that I received today:
Quote: | This submission comes from Sangeeth from Bangalore, India:
The dirs command, combined with pushd and popd, is very effective for tracking users' directory changes. Suppose you have to make some changes to the files present in the following directories:
Instead of noting down the directories on paper, do the following:
Code: | $ pushd /home/sangeeth/soft/release2/src/ |
Code: | $ pushd /home/sangeeth/soft/release2/src/show/ |
Code: | $ pushd /home/sangeeth/soft/release2/doc/ |
To list all the directories, do the following:
The above command removes the topmost directory entry (/home/sangeeth/soft/release2/src/) and performs a cd to the new top directory, which in my case, will be the second directory (/home/sangeeth/soft/release2/src/show/).
Alternatively, one can pop a particular directory from the list of directories by giving the directory ID (the ID is displayed beside a directory when using dirs -l -p -d) to the popd command:
More options available for using the above commands can be found by viewing the man pages. |
|
|
Back to top |
|
d_riordan Member

Joined: 08 Jan 2025 Posts: 245 Location: Leominster, Massachusetts, U.S.A.
|
|
Back to top |
|
masinick Linux Guru

Joined: 03 Apr 2025 Posts: 8615 Location: Concord, NH
|
Posted: Thu Oct 11, 2025 5:40 pm Post subject: Use them for directory navigation |
|
|
d_riordan wrote: | I was a little puzzled about these commands for a minuet. Typing
et. al. produced nothing on my Ubuntu laptop, but searching through
found them as builtin commands.
I'm less puzzled now, but I'm still trying to imagine where or why I would use them . . .  |
You would only use these commands if, first of all, you are a frequent shell user (Bash, or equivalent shell that has these functions - I believe a couple shells do have pushd, popd, and dirs functions). Secondly, even if you are a shell user, you use them only if you create a hierarchy of directories and navigate through them a lot.
Lately I rarely navigate directories. However, I implemented functions similar to these in the Korn Shell years ago, then ported them to my bash shell resource file, .bashrc.
Below are the contents of my .bashrc file. Note the functions g, gb, etc. These implement similar functions but use really short names for typing convenience.
Code: | # File: ~/.bashrc
# Author: Brian Masinick
# Created on: Fri Jan 06 09:26:19 2025
PS1="\u@\h\n\w \@ [\!] > "
export PATH=$PATH:/usr/local/bin:/usr/ccs/bin:~/bin:.
# Author:
# Brian W. Masinick
# Purpose: Set resources, environment, alias, and prompts
# for the Bash shell.
# Defines variables, aliases, and functions for shortening typing
# and tasks. Used with the Bourne Again Shell, bash, from the GNU
# project of the Free Software Foundation.
#
# NOTE: This file is an adaptation of my .kshrc file, removing things
# that are peculiar to the Korn Shell, ksh.
#
# Conventions:
# I define every procedure and function using UpperCase Words Like
# this and prepend each name with TheMas to reduce the likelihood of
# a naming collision with a command, script, or program.
# The procedures are invoked at the bottom of the file. The
# functions or procedures can be called at any time by any
# procedure, which is why breaking the procedures and functions into
# similar groupings makes sense. The organization of the procedures
# may need to be adjusted periodically to keep in step with my
# current work.
# exit if not interactive
case "$-" in
*i*) ;;
*) return ;;
esac
TheMasPoolTools() # define pool and tool directory variables
{
#
# define some aliases used with sandboxes and/or ODE
#
alias c=clear
alias h=history
alias qa1='ssh -l tssadm fpsfebtibqa1'
alias qa2='ssh -l tssadm fpsfebtibqa2'
alias kd="kdestroy"
alias ki="kinit $PRINCIPAL"
alias kl="klist"
alias mm='make clean;make includes;make depend;make'
alias title=~/bin/title
}
TheMasWebExports() # define the environment variables to be exported.
{
# export the CDROM location so that it can be used from a
# window manager. Whenever an upgrade is performed, be sure to
# do a chmod 644 /dev/cam and chmod 666 /dev/rrz4c.
export CDROM=/dev/rrz4c
}
TheMasPrinters() # define printer aliases
{
#
# Printing aliases...
#
alias lpd='lpr -P doc2 -K2 -N1'
alias lp1='lpr -P doc1 -K2 -N1'
alias lp2='lpr -P doc1 -K2 -N2'
alias lp_doc1='lpr -P doc1 -K2 -N1'
alias lpq_doc1='lpq -P doc1'
alias lpq_doc2='lpq -P doc2'
alias lp_l='lpr -P doc1 -O landscape'
}
TheMasMisc() # miscelaneous aliases I like to use
{
alias bye='clear; kill -1 0'
alias c="clear;pwd"
alias cls=clear sd=cd
alias lo='clear; kill -1 0'
alias m='more'
# miscelaneous miscelany...
alias help=apropos
alias wn='who -uT | fgrep .'
# history aliases...
alias h='fc -l'
alias re='fc -e -'
alias zaphist="rm -f /tmp/.mas_history"
# host aliases...
alias host=hostname
alias rw="rwho | sort +1"
# desktop office tool aliases...
alias bh='exec /bin/bash'
alias e=emacs
alias kh='exec /bin/ksh'
alias n=next
alias null=~/null.bash
alias p=prev
alias R='repl -cc all -filter ~/.mhfilter'
alias um=UnseenMail
}
TheMasFileManagement() # commands I use to operate on files and dirs.
{
# directory movement aliases...
alias cd='g'
alias home=cd
# file management aliases...
alias del="rm -i"
alias copy=cp
alias del='rm -i'
alias dir="ls -aqFC"
alias type=cat
alias l='ls -aqCF'
alias lsd='ls -algFqd'
alias lsf='ls -F'
alias lsi='ls -algFqi'
alias lsl="ls -algFq"
alias lsr='ls -aqCFR'
alias lst="ls -algsFqt"
alias lst10="lst | head -10"
alias lst20="lst | head -20"
alias lst30="lst | head -30"
alias lst40="lst | head -40"
alias lst50="lst | head -50"
alias lst60="lst | head -60"
alias lst70="lst | head -70"
alias pdw=pwd
alias pd=pwd
alias wpd=pwd
}
TheMasTerm()
{
alias vt52="TERM=vt52; export TERM"
alias vt100="TERM=vt100; export TERM"
alias vt102="TERM=vt102; export TERM"
alias vt200="TERM=vt200; export TERM"
alias vt300="TERM=vt300; export TERM"
alias vt400="TERM=vt400; export TERM"
alias xrs='set noglob; eval `resize -s \!\*`; unset noglob'
alias xs='set noglob; eval `resize`; unset noglob'
}
TheMasWorkon()
{
####################################################################
#
# Tom Woodburn's stuff (adapted) below...
#
####################################################################
export HISTFILE=/tmp/.mas_bash_history
export HISTSIZE=15000
HOST=`hostname`
# Strip off domain name; e.g., change flume.zk3.dec.com to flume.
HOST=`expr "$HOST" : '\([^\.]*\)'`
export HOST
esac
# PS1="[$HOST:(`whoami`) $SANDBOX($SET)] "
# if DISPLAY exists, set titlebar and icon.
if [ -n "$DISPLAY" ]; then
~/bin/title "Sandbox set $PS1 for $USER" $HOST
fi
unset LANG
;;
esac
}
TheMasHosts() # define host aliases...
{
# rl is a procedure in my bin directory that alters the title bar,
# then calls rlogin.
alias fpsdevbld1='ssh -l tssadm fpsdevbld1'
alias fpsfebtibqa1='ssh -l tssadm fpsfebtibqa1'
alias fpsfebtibqa2='ssh -l tssadm fpsfebtibqa2'
alias fpstibqa031='ssh -l tssadm fpstibqa031'
alias fpstibqa051='ssh -l tssadm fpstibqa051'
alias fpstibqa091='ssh -l tssadm fpstibqa091'
alias fpstibqa092='ssh -l tssadm fpstibqa092'
alias fpstibqa111='ssh -l tssadm fpstibqa111'
alias fpstibqa112='ssh -l tssadm fpstibqa112'
alias fpstibqa121='ssh -l tssadm fpstibqa121'
alias fpsadpqa001='ssh -l tssadm fpsadpqa001'
}
#########################################################################
#
# Bill Gray's functions (adapted) below...
#
#########################################################################
# directory stack functions
declare -i DNUM=0
DLIST[DNUM]=`pwd`
function g # go to a directory
{
if builtin cd "$@" >/dev/null && [ ${DLIST[DNUM]} != "$PWD" ]
then
DNUM=DNUM+1
DLIST[DNUM]=$PWD
fi
case $WORKON in
"")
# if DISPLAY exists, then set titlebar and icon.
if [ -n "$DISPLAY" ]; then
titlebar="$USER @ $HOST : $PWD"
~/bin/title "$titlebar" "$HOST"
fi
;;
*)
;;
esac
pwd
}
function gb # go back
{
if (( $DNUM > 0 ))
then
DNUM=DNUM-1
fi
g ${DLIST[DNUM]}
}
function gn # go to selected (nth) dir
{
select DIR in `echo ${DLIST[*]} | tr " " "\012" | sort -u -y0`
do
if [ "$DIR" ]
then
g $DIR
else
g $REPLY
fi
break
done
}
function up # go up n levels
{
declare -i levels
levels=${1}
if [ -z "${1}" ] && [ ${PWD} != "/" ]
then
g ..
return $?
fi
while [ ${levels} -gt 0 ] && [ ${PWD} != "/" ]
do
g ..
levels=levels-1
done
}
function lpit
{
for file in $*
do
pr -e8 -f $file | lpr -J $file -P doc1
done
}
function lpsrc
{
for file in $*
do
pr -e8 -f -n5 $file | lpr -J $file -P doc1
done
}
function lp_2sides
{
for file in $*
do
pr -e8 -f -n5 $file | lpr -J $file -P doc1 -K 2
done
}
function lp_2sides_2up
{
for file in $*
do
pr -e8 -f -n5 $file | lpr -J $file -P doc1 -K 2 -N 2
done
}
function t
{
export TERM=$1
xs
}
function addpath
{
PATH=$PATH:$1
echo $PATH
}
function log
{
echo `date '+%D %H:%M'` >> ~/.logfile
echo "$*" >> ~/.logfile
echo >> ~/.logfile
date
}
function todo
{
echo `date '+%D %H:%M'` >> ~/todo
echo "$*" >> ~/todo
echo >> ~/todo
}
function rot13
{
tr [a-z][A-Z] [n-z][a-m][N-Z][A-M]
}
function unrot13
{
tr [a-m][n-z][A-M][N-Z] [n-z][a-m][N-Z][A-M]
}
# Remove files that are a symbolic link to some other file, (eg. UnLink)
function UL
{
for i in $*
do
if [ -L $i ]; then
f=`ls -al $i | sed "s/^.*-> //"`
rm -f $i
cp $f $i
fi
done
}
#########################################################################
#
# Call the routines that I use each time that I login.
#
#########################################################################
# Main # <--- Main
# Set the default directory and file protection mask. By default, do
# not mask any protection on my ownership, but remove default write
# access for the group, and do not give "world" any default access.
export SHELL=/bin/bash
umask 022
OS=$(uname)
myterm=$(who am i)
myterm=$(echo $myterm | awk -F" " '{ print $2 }')
echo "The current HOST is $HOST"
echo "The current terminal is $myterm"
echo "The current shell is $SHELL"
echo "The terminal type is $TERM";echo "";echo ""
isLAT=$(echo $myterm | awk '{ print substr($0,1,3) }')
# The following condition checks to see if we are operating in a CDE
# "DT", that is, a CDE Desktop environment. If we are, then we do not
# want to set terminal characteristics. But if we are running a
# terminal emulator, such as dtterm, dxterm, or xterm, then we DO want
# to perform the following steps:
if [ ! "$DT" ]; then
tty -s
# if test $? = 0
# then
# stty
# fi
# tset -Q -I
#
# Define the default editing mode
#
set editing-mode emacs
set show-all-if-ambiguous
fi
TheMasPoolTools
TheMasWebExports
TheMasPrinters
TheMasMisc
TheMasFileManagement
TheMasTerm
TheMasWorkon
TheMasHosts
return # get out of any functions I may be in
# Finished .bashrc |
|
|
Back to top |
|
d_riordan Member

Joined: 08 Jan 2025 Posts: 245 Location: Leominster, Massachusetts, U.S.A.
|
Posted: Fri Oct 12, 2025 5:53 am Post subject: Re: Use them for directory navigation |
|
|
masinick wrote: | You would only use these commands if, first of all, you are a frequent shell user (Bash, or equivalent shell that has these functions - I believe a couple shells do have pushd, popd, and dirs functions). Secondly, even if you are a shell user, you use them only if you create a hierarchy of directories and navigate through them a lot. |
Maybe I'm starting to understand. It's begining to look like
on steroids. Am I in the ballpark here? Probably a little less useful with TAB completion, I would assume.
_________________ *buntu 8.04
|
|
Back to top |
|
masinick Linux Guru

Joined: 03 Apr 2025 Posts: 8615 Location: Concord, NH
|
Posted: Fri Oct 12, 2025 3:36 pm Post subject: Re: Use them for directory navigation |
|
|
d_riordan wrote: | masinick wrote: | You would only use these commands if, first of all, you are a frequent shell user (Bash, or equivalent shell that has these functions - I believe a couple shells do have pushd, popd, and dirs functions). Secondly, even if you are a shell user, you use them only if you create a hierarchy of directories and navigate through them a lot. |
Maybe I'm starting to understand. It's begining to look like
on steroids. Am I in the ballpark here? Probably a little less useful with TAB completion, I would assume. |
The Bash implementation of cd is pretty rich. Tab completion makes directory handling pretty straightforward. Having a stack containing a list of all the directory entries that have been visited is useful. Korn Shell does have one substitution feature:
cd <old> <new> where you provide just the part of the path that you want to change, keeping the remainder of the path intact. I've not noticed that feature being implemented in Bash (though it may have snuck into the most recent versions post V3.0). With the stack feature in Bash, you can do without this feature. With the functions I provided, you have really powerful (steroid) feature directory movement with either Ksh or Bash.
Bottom line is that Ksh, Bash, and Zsh directory navigation is much more powerful than other implementations of the shell, though tcsh, a Csh derivative, has added many of these features and is the only C shell that is even remotely close to useful for anything more than routine interactive use. The POSIX based sh derived shells are MUCH better for writing scripts. I recommend avoiding C shell based shell scripts, including tcsh. Because Bash and tcsh do have so many interactive features in common, I don't even recommend using tcsh for any purpose other than routine work. Most Linux users stick with the Bash default, and I think that is a good thing. |
|
Back to top |
|
masinick Linux Guru

Joined: 03 Apr 2025 Posts: 8615 Location: Concord, NH
|
Posted: Fri Oct 12, 2025 3:45 pm Post subject: Korn and Bash differences and doc pointers |
|
|
In Ksh, going back to my previous post, the Korn (ksh) shell does have a feature NOT found in Bash (and I have verified this by examining on line manuals for each. Here is the Korn shell feature not found in Bash:
Quote: | This command can be in either of two forms. In the first form it changes the current directory to arg. If arg is - the directory is changed to the previous directory. The shell variable HOME is the default arg. The variable PWD is set to the current directory. The shell variable CDPATH defines the search path for the directory containing arg. Alternative directory names are separated by a colon ( . The default path is <null> (specifying the current directory). Note that the current directory is specified by a null path name, which can appear immediately after the equal sign or between the colon delimiters anywhere else in the path list. If arg begins with a / then the search path is not used. Otherwise, each directory in the path is searched for arg.
The second form of cd substitutes the string new for the string old in the current directory name, PWD, and tries to change to this new directory.
By default, symbolic link names are treated literally when finding the directory name. This is equivalent to the -L option. The -P option causes symbolic links to be resolved when determining the directory. The last instance of -L or -P on the command line determines which method is used. |
Taken from http://www.cs.princeton.edu/~jlk/kornshell/doc/man93.html
Korn Shell documentation can be found at http://www.kornshell.com/doc/
Bash Shell documentation can be found at http://www.gnu.org/software/bash/manual/bashref.html |
|
Back to top |
|
|