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配合,來實現這個功能。思路如下:
- 建立一個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 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.')
目前為止,程式碼已經實現了。有幾個點需要說明一下。
- 確保機器上安裝了python或python3
- 將
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
:
[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$
如有更簡單的實現方式,歡迎留言