在一些大型项目中,如aosp等,一些文件会隐藏在很深的目录层次中,有时候我们必须cd切到一个很深的目录中,比如我们要看aosp中AMS中相关的源码和文件,可能就要切到如下目录:
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ ls -l ActivityManager*
-rw-rw-r-- 1 zhangjg zhangjg 20293 10月 25 13:26 ActivityManagerConstants.java
-rw-rw-r-- 1 zhangjg zhangjg 8849 10月 25 13:26 ActivityManagerDebugConfig.java
-rw-rw-r-- 1 zhangjg zhangjg 1075887 10月 25 13:26 ActivityManagerService.java
-rw-rw-r-- 1 zhangjg zhangjg 113459 10月 25 13:26 ActivityManagerShellCommand.java
现在我们所在的目录为
~/deve/aosp/framework/base/services/core/java/com/android/server/am
现在我们想切换到如下目录
~/deve/aosp/framework/base/services/core/
就要像下面这样执行命令:
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cd ../../../../../
zhangjg@zjg:~/deve/aosp/framework/base/services/core$
zhangjg@zjg:~/deve/aosp/framework/base/services/core$
在cd
后面跟5个../
,会向上切换到第5级父目录。同理,要切到上面N级父目录,就要在cd
后跟N个../
这是很不方便的。我要从~/deve/aosp/framework/base/services/core/java/com/android/server/am
切到~/deve/aosp/framework/
,就要敲8个../
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cd ../../../../../../../../
zhangjg@zjg:~/deve/aosp/framework$
zhangjg@zjg:~/deve/aosp/framework$
我们的思路是,先看一下cd命令是否有一些选项,可以让我们很方便的切多级父目录。
首先man cd
看一下:
zhangjg@zjg:~/deve/aosp/framework$ man cd
没有 cd 的手册页条目
zhangjg@zjg:~/deve/aosp/framework$
发现没有对应的man手册。
再看一下cd
的参数选项
zhangjg@zjg:~/deve/aosp/framework$ cd --help
bash: cd: --: 无效选项
cd: 用法: cd [-L|[-P [-e]] [-@]] [dir]
zhangjg@zjg:~/deve/aosp/framework$
zhangjg@zjg:~/deve/aosp/framework$ cd --h
bash: cd: --: 无效选项
cd: 用法: cd [-L|[-P [-e]] [-@]] [dir]
zhangjg@zjg:~/deve/aosp/framework$ cd -h
bash: cd: -h: 无效选项
cd: 用法: cd [-L|[-P [-e]] [-@]] [dir]
zhangjg@zjg:~/deve/aosp/framework$
-L -P是和软链接相关的选项,-e -@不知道是什么意思。
我们认为cd 对于一次返回多级父目录是没有更方便的方式的,在google搜索也没有找到。
如果有谁知道,可以留言。
下面我们尝试自己实现一个脚本,可以很方便的返回多级父目录。
首先想到的是python脚本,但是使用python执行shell命令,会创建一个子进程来执行,执行完成后子进程退出,并不会对当前的shell起作用:
Help on built-in function system in module posix:
system(command)
Execute the command in a subshell.
通过代码试一下:
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.system('cd ../../')
0
>>> exit()
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$
用os.system执行cd命令,并不会切换当前shell的目录。
那么我们就采用python和shell配合,来实现这个功能。思路如下:
cdd
,并为cdd
增加执行权限cdd
接收一个整数num
,表示要向上返回的层级数num
保存到一个环境变量BACK_DIR_NUM
中,并export
导出cdd
中调用python脚本,这个python脚本叫做back_dir.py
back_dir.py
中,获取BACK_DIR_NUM
,并根据这个数字拼一个类似../../ ...... ../
的字符串,并返回给cdd
cdd
将环境变量BACK_DIR_NUM
删除cdd
通过调用cd
切换目录cdd
和back_dir.py
中增加一些简单的错误处理代码如下:
cdd:
#!/bin/bash
num=$1
export BACK_DIR_NUM=$num
result=`python3 -c "import back_dir;back_dir.get_back_path()"`
export BACK_DIR_NUM=""
error_prefix="Error"
if [[ $result == $error_prefix* ]]; then
echo $result
else
cd $result
fi
back_dir.py
import os
n = os.getenv('BACK_DIR_NUM')
def get_back_path():
try:
print('../'*int(n))
except (ValueError,TypeError):
print('Error: Pass a number please.')
目前为止,代码已经实现了。有几个点需要说明一下。
back_dir.py
所在的目录追加到PYTHONPATH
环境变量中,并在~/.bashrc
中导出。如我的back_dir.py
放在~/deve/tools/cmds
下,~/.bashrc
有如下配置:export PYTHONPATH=$PYTHONPATH:~/deve/tools/cmds
cdd
脚本所在的目录追加到PATH
环境变量中,并在~/.bashrc
中导出。如我的cdd
放在~/deve/tools/cmds
下,~/.bashrc
有如下配置:export PATH=$PATH:~/deve/tools/cmds
像下面这样使用cdd
:
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ . cdd 8
zhangjg@zjg:~/deve/aosp/framework$
可以看到,执行. cdd 8
后,当前shell就回到了第8级父目录。
注意
cdd
前要加 .
,因为如果不加.
的话,会启动子shell执行cdd
,也就是在子shell中通过cd
切换目录,并不会影响当前的shell:
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cdd 8
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$
zhangjg@zjg:~/deve/aosp/framework/base/services/core/java/com/android/server/am$
==== ===================== 更新 ==========================
只用shell就可以实现,没必要调python:
#!/bin/bash
num=$1
dir=""
for i in `seq 1 $num`
do
dir="$dir../"
done
cd $dir
如有更简单的实现方式,欢迎留言