1. 程式人生 > >Linux shell命令返回多級父目錄

Linux shell命令返回多級父目錄

通過cd切換多級父目錄

在一些大型專案中,如aosp等,一些檔案會隱藏在很深的目錄層次中,有時候我們必須cd切到一個很深的目錄中,比如我們要看aosp中AMS中相關的原始碼和檔案,可能就要切到如下目錄:

[email protected]:~/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/

就要像下面這樣執行命令:

[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cd ../../../../../
[email protected]:~/deve/aosp/framework/base/services/core$ 
[email protected]
:~/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個../

[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cd ../../../../../../../../
[email protected]
:~/deve/aosp/framework$ [email protected]:~/deve/aosp/framework$

調研cd命令是否有更方便的選項

我們的思路是,先看一下cd命令是否有一些選項,可以讓我們很方便的切多級父目錄。

首先man cd看一下:

[email protected]:~/deve/aosp/framework$ man cd
沒有 cd 的手冊頁條目
[email protected]:~/deve/aosp/framework$ 

發現沒有對應的man手冊。

再看一下cd的引數選項

[email protected]:~/deve/aosp/framework$ cd --help
bash: cd: --: 無效選項
cd: 用法: cd [-L|[-P [-e]] [[email protected]]] [dir]
[email protected]:~/deve/aosp/framework$ 
[email protected]:~/deve/aosp/framework$ cd --h
bash: cd: --: 無效選項
cd: 用法: cd [-L|[-P [-e]] [[email protected]]] [dir]
[email protected]:~/deve/aosp/framework$ cd -h
bash: cd: -h: 無效選項
cd: 用法: cd [-L|[-P [-e]] [[email protected]]] [dir]
[email protected]:~/deve/aosp/framework$ 

-L -P是和軟連結相關的選項,-e [email protected]不知道是什麼意思。 我們認為cd 對於一次返回多級父目錄是沒有更方便的方式的,在google搜尋也沒有找到。 如果有誰知道,可以留言。

自己實現返回多級父目錄

下面我們嘗試自己實現一個指令碼,可以很方便的返回多級父目錄。

首先想到的是python指令碼,但是使用python執行shell命令,會建立一個子程序來執行,執行完成後子程序退出,並不會對當前的shell起作用:

Help on built-in function system in module posix:

system(command)
    Execute the command in a subshell.

通過程式碼試一下:

[email protected]:~/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()
[email protected]:~/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 CK_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

[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ . cdd 8
[email protected]:~/deve/aosp/framework$ 

可以看到,執行. cdd 8後,當前shell就回到了第8級父目錄。

注意 cdd前要加 .,因為如果不加.的話,會啟動子shell執行cdd,也就是在子shell中通過cd切換目錄,並不會影響當前的shell:

[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ cdd 8
[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$ 
[email protected]:~/deve/aosp/framework/base/services/core/java/com/android/server/am$

如有更簡單的實現方式,歡迎留言