最近公司項(xiàng)目代碼從gogs遷移到gitlab上,項(xiàng)目中大量的pod子組建里的podspec配置,git配置,還有各種腳本里的服務(wù)器地址都需要替換。所以就寫了python腳本全局替換。無意中發(fā)現(xiàn)前同事遺留下來的shell腳本,看上去比python簡(jiǎn)潔得多,其中一個(gè)sed命令引起我的注意,于是研究了一下,確實(shí)強(qiáng)大。本文主要記錄使用sed,grep,xargs工具由簡(jiǎn)到繁最終解決問題的過程,以及自我總結(jié)。
sed簡(jiǎn)介
SED的英文全稱是 Stream EDitor,它是一個(gè)簡(jiǎn)單而強(qiáng)大的文本解析轉(zhuǎn)換工具,在1973-1974年期間由貝爾實(shí)驗(yàn)室的Lee E. McMahon開發(fā),今天,它已經(jīng)運(yùn)行在所有的主流操作系統(tǒng)上了。
SED的典型用途
- 文本替換
- 選擇性的輸出文本文件
- 從文本文件的某處開始編輯
- 無交互式的對(duì)文本文件進(jìn)行編輯等
示例(Example)
- 匹配鏈接
sed -n '/http:\/\/.*\/[a-zA-Z]*\.git/ p' UpdatePodScript.sh
在文件UpdatePodScript.sh匹配
項(xiàng)目的git地址,p命令是指打印匹配結(jié)果,-n指禁止輸入文件讀入sed模式空間時(shí)默認(rèn)輸出,避免重復(fù)輸出,一般-n與p同時(shí)使用。
- 匹配目標(biāo)(需要替換)部分
sed -n 's|http:\/\/\(.*\)\/[a-zA-Z]*\.git|\1| p' UpdatePodScript.sh
// 匹配完整的git鏈接
sed -n 's/\(http:\/\/\)\(.*\)\(\/[a-zA-Z]*\.git\)/\1GogsAddress\3/ p' UpdatePodScript.sh
// 用|,@,^,!進(jìn)行分隔,去除\轉(zhuǎn)義符,便于閱讀
sed -n 's@\(http://\)\(.*\)\(/[a-zA-Z]*\(\.git\)\{0,1\}\)@\1GogsAddress\3@ p' LYHttpManager.podspec
括號(hào)內(nèi)就是你需要替換的內(nèi)容,
\1是括號(hào)內(nèi)內(nèi)容的別稱,如果有多個(gè)括號(hào)對(duì)應(yīng)別稱就是順延\1、\2、\3、... 注意這里括號(hào)需要轉(zhuǎn)義\(xxx\)。
- 匹配并替換目標(biāo)部分
sed -i '' 's@\(http://\)\(.*\)\(/[a-zA-Z]*\(\.git\)\{0,1\}\)@\1GogsAddress\3@g' LYHttpManager.podspec
-i:直接修改讀取的文件內(nèi)容,而不是輸出到終端。
'':取消因?yàn)閙ac系統(tǒng)對(duì)sed命令要求的強(qiáng)制備份。
s:替換命令,格式'/s/oldstring/newstring',將oldstring替換成newstring,默認(rèn)只替換文件里的第一個(gè)oldstring。
g:替換文件里的全部oldstring。
這里有一個(gè)問題,sed正則是不是不支持
?,+,我試過匹配不出來。
- 匹配替換grep搜索的所有結(jié)果(最終命令)
grep -rl 'GitLabAddress' . | sed 's/ /\\ /g' | xargs sed -i '' 's@\(http://\)\(.*\)\(/[a-zA-Z]*\(\.git\)\{0,1\}\)@\1GogsAddress\3@g'
// 因?yàn)槭?對(duì)1的替換,所以不需要正則匹配,把正則換成鏈接字符串。
grep -rl 'GogsAddress' . | sed 's/ /\\ /g' | xargs sed -i '' 's@GogsAddress@GitLabAddress@g'
-r:遍歷目錄及所有子目錄。
-l:只顯示符合條件的文件名(包含路徑)
整個(gè)命令通過|分為三部分:
- 獲取包含'GogsAddress'字符串的所有文件名。
- 將路徑中空格' '轉(zhuǎn)義成'\ '.
- 將'GogsAddress'替換成'GitLabAddress'。
sed與python
- sed
grep -rl 'GogsAddress' . | sed 's/ /\\ /g' | xargs sed -i '' 's@GogsAddress@GitLabAddress@g'
- python
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import os
import re
import sys
# profile文件目錄
# ROOT_PATH = '/Users/wans/Documents/iOSUser/Code/LYLawyerPlatform_User'
GITLAB_HOST_ADDRESS = "GitLabAddress"
ROOT_PATH = os.getcwd()
def replace_address(address):
fo = open(address,'r+')
content = fo.read()
pattern = re.compile(r'http://(.+)/(\w+)(\.git)*')
match = pattern.search(content)
if match:
old_module_address = match.group(1)
content = content.replace(old_module_address,GITLAB_HOST_ADDRESS)
fo = open(address, 'w')
fo.write(content)
fo.flush()
if fo:
fo.close()
def main():
files = os.listdir(ROOT_PATH)
for subdir in files:
subdir = os.path.join(ROOT_PATH,subdir)
if os.path.isdir(subdir):
module_files = os.listdir(subdir)
# 遍歷子項(xiàng)目
for module_subdir in module_files:
module_subdir = os.path.join(subdir,module_subdir)
if module_subdir.endswith('.git'):
module_dir = os.path.join(module_subdir,"config")
print module_dir
if os.path.exists(module_dir):
replace_address(module_dir)
if module_subdir.endswith('Example'):
module_dir = os.path.join(module_subdir,"Podfile")
print module_dir
if os.path.exists(module_dir):
replace_address(module_dir)
if module_subdir.endswith('.podspec'):
print module_subdir
replace_address(module_subdir)
if module_subdir.endswith('UpdatePodScript.sh'):
print module_subdir
replace_address(module_subdir)
if __name__ == '__main__':
main()
沒有比較兩個(gè)工具好壞的意思,只是直觀比較而已??。
最終一行命令解決問題,而我寫的python腳本幾十行,重點(diǎn)是sed只在終端運(yùn)行就可以,只在終端運(yùn)行就可以,只在終端運(yùn)行就可以,所以稱sed為代碼屠夫也不為過。雖然sed命令簡(jiǎn)潔,但是不太明了,光那轉(zhuǎn)義符都看得頭暈,可讀性不高。but,我還是傾向于用sed解決問題,恩,沒有為什么。??
以上
完全現(xiàn)學(xué)現(xiàn)用,見笑了,就算拋磚引玉吧。