简介
最近常在服务器上跑任务,但是服务器上跑过的任务太多,工作目录下很多项目的文件,路径也较长,每次进入目标文件夹的时候,即使用tab补全也需要花很多时间来输入绝对路,而每个项目需要的文件夹较少,就固定那么几个,就希望能够暂时将近期常用的文件夹路径暂时存起来,以便调用,换下个项目的时候也可以用新的路径替代老的路径,于是想到了目录栈。
Linux目录栈操作
Linux目录栈常用命令有三个,dirs:用于打印目录栈,pushd:用于目录栈的写入和调用,popd:用于目录栈的删除。
dirs
dirs命令可以打印当前目录栈下的全部内容。
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs
~ ~/dir2 ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -l
/home/yangzhuoxuan /home/yangzhuoxuan/dir2 /home/yangzhuoxuan/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -p
~
~/dir2
~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -v
0 ~
1 ~/dir2
2 ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -lv
-bash: dirs: -lv: invalid number
dirs: usage: dirs [-clpv] [+N] [-N]
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -l -v
0 /home/yangzhuoxuan
1 /home/yangzhuoxuan/dir2
2 /home/yangzhuoxuan/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -c
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs
~
dirs : 打印当前目录栈内容。
-l : 显示完整绝对路径,注意第一条是当前路径。
-p : 分行打印多条路径。
-v : 与 -p 相同,都是分行打印多条路径,但是 -v 参数会在每行前加上索引,可读性更高。其中序号0为当前路径。
-c : 清空当前目录栈。由于目录栈第一条是当前路径,清空以后只剩下当前路径。
补充:dirs命令与ls不同,参数不可以合在一起,如果想要分行显示完整绝对路径,需要 -l -v ,不可以 -lv。
补充:dirs -v命令更直观常用,但是命令太长还需要参数不方便输入,可以在配置中别名为dv。
pushd
pushd命令可以将路径写入目录栈,也可以进入目录栈中的路径。
※ 由于目录栈第一条( index 为 0 )为当前路径,所以在目录栈第一条路径发生改变时,当前路径也会随之改变到目标路径。
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dv
0 ~
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ pushd dir1
~/dir1 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ pushd ~/dir2
~/dir2 ~/dir1 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir2]$ dv
0 ~/dir2
1 ~/dir1
2 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir2]$ pushd
~/dir1 ~/dir2 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ dv
0 ~/dir1
1 ~/dir2
2 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ pushd +1
~/dir2 ~ ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 dir2]$ pushd +2
~/dir1 ~/dir2 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ dv
0 ~/dir1
1 ~/dir2
2 ~
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ pushd -0
~ ~/dir1 ~/dir2
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dirs -c
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ pushd -n ~/dir1
~ ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ pushd -n lalalala
~ lalalala ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ pushd +1
-bash: pushd: lalalala: No such file or directory
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ pushd `pwd`
~/dir1 ~/dir1
pushd:调用目录栈内的路径。
直接加路径:将路径加入目录栈的第一条,原目录栈向后顺延。由于改变了第一条路径,当前目录同样发生改变。
不加任何参数:将目录栈 index 为 0 和 1 的路径互调,即目录栈前两条,同时改变当前路径。
+Num:注意+和输入Num中没有空格。将目录栈的 index 为 0 和第 Num (即 index 为 Num )的两条路径互调,同时改变当前路径。互调以后目标路径的 index 为 0 ,如果此时再 cd 更改当前路径,则会改变目录栈中的内容,保存在目录栈中的内容将不复存在。
-Num:同 +Num ,不过 +Num 是从正着数第 Num 的路径,等同于 index 号码,-Num 是倒着数的,类似 tail 操作,除非目录栈过长时调用在后面的路径,否则并不常用。
-n 路径:将输入的文字直接加入目录栈第二条( index 为 1 )。不改变目录栈第一条路径,不更改当前文件夹。注意此操作中不管输入的路径是否存在,都会直接加入目录栈,不进行判断。
补充:如果希望将当前路径加入目录栈,不要使用管道符,可以使用反引号操作。
个人并不是很喜欢这套 pushd 的操作,尤其是会发生当前路径的更改,很不适应,如果 pushd 进入了哪个路径,一旦习惯性 cd 改变了当前文件夹又会损失掉我的目录栈内容。唯一不发生当前路径更改的操作 -n 又不会判断目录是否存在,发生了错误只有切换路径的时候才能发现。
popd
popd命令与pushd的添加功能相反,用于删除目录栈中的内容。
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dv
0 ~
1 ~/dir1
2 ~/dir2
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ popd
~/dir1 ~/dir2
(base) [yangzhuoxuan@cngb-login-0-1 dir1]$ pwd
/home/yangzhuoxuan/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dv
0 ~
1 ~/dir1
2 ~/dir2
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ popd ~/dir2
~ ~/dir1
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ dv
0 ~
1 ~/dir1
2 ~/dir2
(base) [yangzhuoxuan@cngb-login-0-1 ~]$ popd +1
~ ~/dir2
popd:删除目录栈内容
不加任何参数:删除目录栈第一条路径内容,同时改变当前目录。
直接加路径:删除目标路径。
+Num:注意+和输入Num中没有空格。删除目录栈中第 Num (即 index 为 Num )的路径。
-Num:+Num的另一个方向的操作。
-n 路径:删除目标路径。
补充:如果 popd 后面添加路径不存在,则会删除目录栈最后一条路径。如果目录栈中有不存在的路径, popd 直接加相同不存在的路径内容,依旧会删除最后一条路径而不删除同名内容,使用 -n 路径 的参数则可以删除同名内容。
自己改进的目录栈
Linux自带的目录栈由于种种问题,并不能很好的满足我日常使用。第一,对于一个更改目录使用 cd 成习惯的人,经常在添加目录栈时产生不必要的当前目录跳转,和将目录栈内容的修改,对于个人使用而言,将当前工作目录和目录栈的 index 0 联系起来只带来了许多麻烦。第二, pushd 压入目录栈操作不能保证目录栈中的内容不重复,第三,目录栈对于我最大的不方便在于目录栈不能永久储存,每次重启服务器就会消失,打开多个服务器页面又不能同步。
于是产生了针对自己的需要改进一下目录栈的想法。需要一个文件来储存目录路径,同样类似linux目录栈的操作,需要可以对其打印、目标路径调用,压入和弹出四个操作。
#!/usr/bin/bash
#目录栈存储位置
ds_file=/home/yangzhuoxuan/data/lib/DirectoryStack/list
#不加参数则打印当前目录栈
if [ "$*" == "" ];then
cat -n ${ds_file}
#参数[-cdn]
elif [[ $1 == -* ]];then
#参数-n加数字,转到第几个路径
##如果路径不存在则从目录栈中删除,防止文件夹删除而目录栈中未删除
if [ $1 == -n ];then
if [[ $2 =~ ^[0-9]+$ ]];then
dir_name=`sed -n "${2}p" ${ds_file}`
if [ -d ${dir_name} ];then
echo ${dir_name}
cd ${dir_name}
else
echo "${dir_name} does not exist or is not a directory! Path deleted!"
sed -i "${2}d" ${ds_file}
fi
else
echo "$2 is not a number!"
fi
#参数-d加数字,从目录栈中删除第几个路径
elif [ $1 == -d ];then
if [[ $2 =~ ^[0-9]+$ ]];then
dir_name=`sed -n "${2}p" ${ds_file}`
echo "Path ${dir_name} deleted!"
else
echo "$2 is not a number!"
fi
#参数-c清空目录栈
elif [ $1 == -c ];then
> ${ds_file}
else
echo "ds: usage: ds [-cdn] or ds pathname"
fi
#直接加路径,如果路径存在则加入目录栈
##如果路径已在目录栈中则提高位次到第一位
elif [ -d $1 ];then
dir_name=`lp $1`
grep_result=`grep -n ^${dir_name}$ ${ds_file}`
if [ "${grep_result}" != "" ];then
sed -i "${grep_result%%:*}d" ${ds_file}
fi
if [ -s ${ds_file} ];then
sed -i "1i${dir_name}" ${ds_file}
else
echo ${dir_name} > ${ds_file}
fi
cat -n ${ds_file}
else
echo "$1 does not exist or is not a directory!"
fi
简单写了个脚本以完成所需要的操作,将脚本放入bin文件下并赋予可执行权限。
注意:需要储存目录栈的文件存在,虽然- c 参数可以产生文件,但是没有判断其路径的存在。
注意:对于切换当前文件夹操作需要在父进程下运行,建议将“ . ds -n ”在配置文件中别名,以方便切换路径操作。
不算别名的话,用一个命令就可以完成这些操作了,虽然没有linux的目录栈操作功能丰富,但总之能很好的满足我的需求了,而且没有了会偶联当前路径的烦恼,更符合我的操作习惯。也许这个方法效率不是最高的,但是能实现功能就好嘛。终于写好了,上来就先把最近常用的文件夹路径和bin文件路径加在里面了,终于免去了反复输入那些超长路径的烦恼,爽!