Linux shell命令返回多级父目录

Linux shell命令返回多级父目录

    • 通过cd切换多级父目录
    • 调研cd命令是否有更方便的选项
    • 自己实现返回多级父目录
    • 使用方法
    • 简化版本

通过cd切换多级父目录

在一些大型项目中,如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命令是否有更方便的选项

我们的思路是,先看一下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配合,来实现这个功能。思路如下:

  1. 创建一个shell脚本cdd,并为cdd增加执行权限
  2. cdd接收一个整数num,表示要向上返回的层级数
  3. num保存到一个环境变量BACK_DIR_NUM中,并export导出
  4. cdd中调用python脚本,这个python脚本叫做back_dir.py
  5. back_dir.py中,获取BACK_DIR_NUM,并根据这个数字拼一个类似../../ ...... ../的字符串,并返回给cdd
  6. cdd将环境变量BACK_DIR_NUM删除
  7. cdd通过调用cd切换目录
  8. cddback_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.')  

目前为止,代码已经实现了。有几个点需要说明一下。

  1. 确保机器上安装了python或python3
  2. back_dir.py所在的目录追加到PYTHONPATH环境变量中,并在~/.bashrc中导出。如我的back_dir.py放在~/deve/tools/cmds下,~/.bashrc有如下配置:
export PYTHONPATH=$PYTHONPATH:~/deve/tools/cmds
  1. 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


如有更简单的实现方式,欢迎留言

你可能感兴趣的:(Linux,Python)