不知道你有没有和我一样的需求,平常会负责几个项目的开发,又习惯使用git命令行管理开发代码。每次要提交代码,都要找到项目的目录,然后打开一个命令行窗口,或者频繁切换目录到想要的目录,到最后,你的任务栏可能有N个git命令行窗口,虽然操作也没那么麻烦,但是做重复的事总是很不舒服。
所以简单的写了个bash脚本,方便切换目录,虽然简单,但是用着还觉得挺方便的,有兴趣的可以看下,https://github.com/eussi/SimpleScripts/tree/master/gitTools。
我用的电脑是windows系统,在我电脑上开发环境是这样的,自己有个工作目录,负责的项目都放在这个目录下面,每个项目有他自己的标识。假设这个目录是APP,下面A,B,C等项目,目录层级可能如下:
./APP
./APP/aaaa
./APP/aaaa/aaaa
./APP/aaaa/aaaa/app.properties
./APP/bbbbb
./APP/bbbbb/app.properties
./APP/cccccccc
./APP/cccccccc/app.properties
./APP/dddd
标识每个项目信息的文件是app.properties,文件里内容可能包含appid等应用的数据,文件内容可能是这样:
appid=100012345
bb=e
cc=3
当然文件app.properties可能不存在,文件中的appid也可能不存在。
#1
刚刚开始想法是这样的,需要有一个命令,这个命令不能很长,传入工作目录,这个命令会将所有项目以列表的形式展示出来,然后自己输入想进入哪个项目目录,就可以立刻进入,并且这个命令可以在电脑的任何一个目录下执行。
这样我随时打开git,随时切换目录,即使在一个项目的目录中,也可以切换到另外一个项目的目录下。
‘很短的命令’可以通过alias别名来实现,逻辑可以通过bash脚本来实现,切换当前所在目录,可以通过source或.
执行bash脚本来实现。
于是有了下面一个版本的脚本list_v1.sh
:
#!/bin/bash
#program:
# Switch application directory
#author:
# xuemingwang 2020-11-21
#usage:
# source list_v1.sh dir
#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"
#print func
printMsg() {
mesg=$1
head=$2
tail=$3
echo -e "${head}${mesg}${tail}"
}
ROOT_DIR=$1
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########
#main
main() {
echo ""
echo "******************************"
printMsg "APP_DIR:"$ROOT_DIR $WHITE $BOLD
echo "******************************"
#get list
echo -e "\nLIST:"
index=0
for var in `ls $ROOT_DIR`
do
subDir=$ROOT_DIR"/"$var
if [ ! -d $subDir ]; then
continue
fi
#find appid
appfilePath=`find $subDir -name $APP_FILENAME`
if [ -n "$appfilePath" ]; then
app_arr[index]="["$index"]. "`sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $appfilePath`" "$var
else
app_arr[index]="["$index"]. "$NULL_APPID" "$var
fi
#echo "${app_arr[index]}"
index=$((index+1))
done
#print list
for ((k=0; k<$index; k++))
do
printMsg "${app_arr[$k]}" $WHITE $BOLD
done
#choose where to to
echo "******************************"
echo -e "\nOPTIONS:"
while true
do
echo Please choose where to go or exit by Q:
read input
#echo $input
if [ "Q" = "$input" -o "q" = "$input" ]; then
echo "exit"
#exit 0
break
fi
find=0
for ((k=0; k<$index; k++))
do
echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
if [ $? -eq 0 ]; then
#find
find=1
retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
cd $ROOT_DIR"/"$retDir
break
fi
done
#for remove exit
if [ "$find" = "1" ]; then
break
fi
echo -e "Please enter the string contained in the list.\n"
done
}
if [ ! $# -eq 1 ]; then
echo Usage: with one parameters, the root of application directory.
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
else
main
fi
fi
fi
大致逻辑是遍历工作目录,并通过find命令查找标识文件app.properties,再在文件中提取出appid对应的值,通过列表的形式展示出来。
此时将脚本加入path路径中,我是在home目录里创建了bin目录,即C:\Users\wangx\bin,脚本放在该目录下,然后打开bash命令行通过alias设置命令别名,如下:
$ alias cmds='. list_v1.sh /C/Users/wangx/Desktop/APP'
上面命令用cmds
(cmd switch)代替. list_v1.sh /C/Users/wangx/Desktop/APP
命令,注意运行该命令的时候我使用的.
或者source
, 因为要切换当前执行的目录,使用sh
只能切换子shell的目录,对当前目录切换无效。
这个时候便可以方便切换目录了,操作如下:
$ cmds
******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************
LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************
OPTIONS:
Please choose where to go or exit by Q:
16789
$ pwd
/C/Users/wangx/Desktop/APP/bbbbb
$ cmds
******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************
LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************
OPTIONS:
Please choose where to go or exit by Q:
ddd
$ pwd
/C/Users/wangx/Desktop/APP/dddd
$ cmds
******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************
LIST:
[0]. 100012345 aaaa/
[1]. 100016789 bbbbb/
[2]. 200016789 cccccccc/
[3]. ######### dddd/
******************************
OPTIONS:
Please choose where to go or exit by Q:
q
exit
这样看起来已经完全满足需求了,于是拿到自己电脑上开始使用了,一用就尴尬了,工作目录下一二十个应用,每次要切换目录时,输入命令,展示出来实在是太慢了,还不如我之前直接手动切换。
#2
一方面git的bash命令行执行linux上的一些命令速度确实慢很多,另一方面怀疑自己使用find命令查找appid效率可能太低了,毕竟一个项目中文件可能很多,查找文件数量多起来将会耗时很高,两方面一起算下来,脚本执行速度慢也是理所当然的吧。于是想着先优化下find命令吧。
一般在一个公司,所有的项目的appid存放的位置一般是一样的,比如都在应用根目录下有个app.properties,或者在第二层目录下,所以就没必要通过find搜索一遍了,采用直接读取这两个位置的app.properties,拿到appid,拿不到就结束。即:
getAppId() {
rootDir=$1
filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
#src\main\resources\META-INF\app.properties
if [ -f "$filePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
else
find=0
for var in `ls $ROOT_DIR'/'$rootDir`
do
secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
#echo $secondFilePath
if [ -f "$secondFilePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
find=1
break #At most two layer
fi
done
if [ $find = "0" ]; then
echo $NULL_APPID
fi
fi
}
于是有了第二版脚本list_v2.sh
:
#!/bin/bash
#program:
# Switch application directory
#author:
# xuemingwang 2020-11-21
#usage:
# source list.sh dir
#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"
#print func
printMsg() {
mesg=$1
head=$2
tail=$3
echo -e "${head}${mesg}${tail}"
}
ROOT_DIR=$1
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########
getAppId() {
rootDir=$1
filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
#src\main\resources\META-INF\app.properties
if [ -f "$filePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
else
find=0
for var in `ls $ROOT_DIR'/'$rootDir`
do
secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
#echo $secondFilePath
if [ -f "$secondFilePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
find=1
break #At most two layer
fi
done
if [ $find = "0" ]; then
echo $NULL_APPID
fi
fi
}
#main
main() {
echo ""
echo "******************************"
printMsg "APP_DIR:$ROOT_DIR" $WHITE $BOLD
echo "******************************"
#get list
echo -e "\nLIST:"
index=0
for var in `ls $ROOT_DIR`
do
subDir=$ROOT_DIR"/"$var
if [ ! -d $subDir ]; then
continue
fi
#find appid
#appfilePath=`find $subDir \( -path "./.git" -o -path ".git" -o -path "./.idea" \) -prune -o -name $APP_FILENAME`
appId=`getAppId $var`
#if [ -n "$appfilePath" ]; then
# app_arr[index]="["$index"]. "`sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $appfilePath`" "$var
#else
# app_arr[index]="["$index"]. "$NULL_APPID" "$var
#fi
app_arr[index]=`printf "[%02s]. %-9s %s" "$index" "$appId" "$var"`
printMsg "${app_arr[index]}" $WHITE $BOLD
#echo "${app_arr[index]}"
index=$((index+1))
done
#print list
#for ((k=0; k<$index; k++))
#do
# printMsg "${app_arr[$k]}" $WHITE $BOLD
#done
#choose where to to
echo "******************************"
echo -e "\nOPTIONS:"
while true
do
echo Please choose where to go or exit by Q:
read input
#echo $input
if [ "Q" = "$input" -o "q" = "$input" ]; then
echo "exit"
#exit 0
break
fi
find=0
for ((k=0; k<$index; k++))
do
echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
if [ $? -eq 0 ]; then
#find
find=1
retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
cd $ROOT_DIR"/"$retDir
echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
break
fi
done
#for remove exit
if [ "$find" = "1" ]; then
break
fi
echo -e "Please enter the string contained in the list.\n"
done
}
if [ ! $# -eq 1 ]; then
echo Usage: with one parameters, the root of application directory.
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
else
main
fi
fi
fi
同样将脚本设置放到path目录下,然后设置别名
$ alias cmds='. list_v2.sh /C/Users/wangx/Desktop/APP'
运行效果如下:
$ cmds
******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************
LIST:
[00]. 100012345 aaaa/
[01]. 100016789 bbbbb/
[02]. 200016789 cccccccc/
[03]. ######### dddd/
******************************
OPTIONS:
Please choose where to go or exit by Q:
bbb
CURRENT: /C/Users/wangx/Desktop/APP/bbbbb/
$ pwd
/C/Users/wangx/Desktop/APP/bbbbb
$ cmds
******************************
APP_DIR:/C/Users/wangx/Desktop/APP
******************************
LIST:
[00]. 100012345 aaaa/
[01]. 100016789 bbbbb/
[02]. 200016789 cccccccc/
[03]. ######### dddd/
******************************
OPTIONS:
Please choose where to go or exit by Q:
q
exit
$ pwd
/C/Users/wangx/Desktop/APP/bbbbb
运行没问题,拿到自己电脑上测试,同样的问题,还是运行的太慢,看来命令不是主要的影响因素,之后也尝试网上查找优化git执行命令的速度,但是效果都不大。上面的方案看来并不能解决问题。
#3
因为git执行脚本始终速度都很慢,只能通过其他方法来实现自己的需求了。
再细想想,由于自己负责开发的项目数量和名称变动并不是很大,我可以将信息先缓存起来,等到数据变动时,我再进行更新,并且我也没必要每次列出来之后选择要进入的目录,我还想要一个立刻进入某目录的功能,切换速度更快更方便。
于是想了另外一个方案,修改脚本,传入不同的参数,实现三个功能:
- 将项目数据缓存到某个文件中
- 读取缓存文件,展示数据,选择进入目录
- 读取缓存文件,直接进入目录
这样,直接读取一个缓存文件,然后选择进入某个项目的目录,不至于执行也是龟速吧。于是产生了下面的脚本list_v3.sh
:
#!/bin/bash
#program:
# Switch application directory
#author:
# xuemingwang 2020-11-21
#usage:
# source list_v3.sh dir -g
# source list_v3.sh dir -l
# source list_v3.sh dir -s str
#print format
WHITE="\033[37m"
RED="\033[31m"
BOLD="\033[1m"
#params
INPUT_PARAMS=$@
INPUT_PARAMS_NUM=$#
#variable
TEMP_FILE=/.list_v3
ROOT_DIR=$1
FLAG=$2
FLAG_VALUE=$3
APP_FILENAME=app.properties
APPID_SYMPOL=appid
NULL_APPID=#########
#print func
printMsg() {
mesg=$1
head=$2
tail=$3
echo -e "${head}${mesg}${tail}"
}
getAppId() {
rootDir=$1
filePath=$ROOT_DIR'/'$rootDir'/'$APP_FILENAME
#src\main\resources\META-INF\app.properties
if [ -f "$filePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'=\([0-9]*\)/s//\1/p' $filePath`
else
find=0
for var in `ls $ROOT_DIR'/'$rootDir`
do
secondFilePath=$ROOT_DIR'/'$rootDir'/'$var'/'$APP_FILENAME
#echo $secondFilePath
if [ -f "$secondFilePath" ]; then
echo `sed -n '/^'"$APPID_SYMPOL"'[ ]*=[ ]*\([0-9]*\)/s//\1/p' $secondFilePath`
find=1
break #At most two layer
fi
done
if [ $find = "0" ]; then
echo $NULL_APPID
fi
fi
}
#Generate temporary cache
generate() {
tempFile=$TEMP$TEMP_FILE
> $tempFile
index=0
for var in `ls $ROOT_DIR`
do
subDir=$ROOT_DIR"/"$var
if [ ! -d $subDir ]; then
continue
fi
appId=`getAppId $var`
printf "%-9s %s\n" "$appId" "$var" >> $tempFile
index=$((index+1))
done
}
#List the options
list() {
tempFile=$TEMP$TEMP_FILE
if [ ! -f $tempFile ]; then
echo "err: need a temporary document."
else
echo -e "\nLIST:"
index=0
while read line
do
app_arr[index]=`printf "%02s %s" "$index" "$line"`
echo ${app_arr[index]}
index=$((index+1))
done < $tempFile
echo -e "\nOPTIONS:"
while true
do
echo Please choose where to go or exit by Q:
read input
#echo $input
if [ "Q" = "$input" -o "q" = "$input" ]; then
echo "exit"
#exit 0
break
fi
find=0
for ((k=0; k<$index; k++))
do
echo "${app_arr[$k]}" | grep "$input" > /dev/null 2>&1
if [ $? -eq 0 ]; then
#find
find=1
retDir=`echo ${app_arr[$k]} | awk '{print $3}'`
cd $ROOT_DIR"/"$retDir
echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
break
fi
done
#for remove exit
if [ "$find" = "1" ]; then
break
fi
echo -e "Please enter the string contained in the list.\n"
done
fi
}
#Switch directory
switch(){
tempFile=$TEMP$TEMP_FILE
if [ ! -f $tempFile ]; then
echo "err: need a temporary document."
else
find=0
while read line
do
echo "$line" | grep "$FLAG_VALUE" > /dev/null 2>&1
if [ $? -eq 0 ]; then
#find
find=1
retDir=`echo ${line} | awk '{print $2}'`
cd $ROOT_DIR"/"$retDir
echo -e "\nCURRENT: "$ROOT_DIR"/"$retDir
break
fi
done < $tempFile
if [ "$find" != "1" ]; then
echo -e "No such app dir.\n"
fi
fi
}
#main
main() {
if [[ $FLAG != -* ]]; then
FLAG_VALUE=$FLAG
FLAG="-s" #default value -s
fi
case $FLAG in
"-l")
list
;;
"-g")
generate
;;
"-s")
switch
;;
*)
echo "Unsupported commands."
;;
esac
}
#basic check
if [ $# -gt 3 ]; then
echo Usage: Up to three parameters, root_dir, flag and the value.
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
#exit -1 #Exit cannot be used in order to switch execution directories
else
if [ ! -d $ROOT_DIR ]; then
echo $ROOT_DIR "is not exist."
else
main
fi
fi
fi
同样将脚本设置放到path目录下,然后设置三个功能的别名
$ alias cmdg='sh list_v3.sh /C/Users/wangx/Desktop/APP -g'
$ alias cmdl='. list_v3.sh /C/Users/wangx/Desktop/APP -l'
$ alias cmds='. list_v3.sh /C/Users/wangx/Desktop/APP -s'
执行效果如下:
$ cmdg
$ cmdl
LIST:
00 100012345 aaaa/
01 100016789 bbbbb/
02 200016789 cccccccc/
03 ######### dddd/
OPTIONS:
Please choose where to go or exit by Q:
bb
CURRENT: /C/Users/wangx/Desktop/APP/bbbbb/
$ cmds aaa
CURRENT: /C/Users/wangx/Desktop/APP/aaaa/
$ cmds 2000
CURRENT: /C/Users/wangx/Desktop/APP/cccccccc/
$ pwd
/C/Users/wangx/Desktop/APP/cccccccc
其中cmdg生成文件内容如下:
$ cat $TEMP/.list_v3
100012345 aaaa/
100016789 bbbbb/
200016789 cccccccc/
######### dddd/
如果你往工作目录里添加了新的项目,运行一下cmdg
更新下这个文件,然后又可以使用cmdl
和cmds
切换目录了,速度完全能达到需求。
终于算是搞定了。
使用了大概一个月了,确实用着比之前舒服多了。
另外,如果你有多个工作目录,这个脚本也可以使用,你可以将别名设置成不同的名字,来操作不同目录。不过需要注意的是,存放生成的文件要调整,否则会相互覆盖,可以将传入工作目录的字符串进行hash,然后拼接到生成文件名的后面来做区分。不过目前我这里这样就够了,就不多搞了。