[Py] 將地球科學繪圖上課用的範例轉為bash的程式

地球科學繪圖是由胡老師開的一門課,主要介紹使用通用製圖工具–Generic Mapping Tool 進行地球科學相關資料的繪圖工作。本文是記錄在修課時,由於本身使用 Mac 環境工作,然而範例都是以 Windows 的 Batch 環境為主,故寫了一個小小的 Python 程式來做轉換。

所需程式:基本上 Linux 系統都有內建 Python 2,應該不用額外安裝
  • Python:2.6 以上,在 2.7.10 執行無誤,3以上版本未測試(print未更改)
使用說明:
在命令列中:

$python DosToBash.py input_filename [arguments]

其中 [arguments] 為以下選項,用於控制執行的模式:

    arguments:
    input_filename : Required. 輸入的檔案,必須給的參數且需放在第二個變數
    -p : print out all the lines for inputfile. 純粹列出文字檔所有的內容。
    –help : print help information. 印出使用說明。
    –out=filename : specify the output filename. 指定輸出檔案的檔名,預設為filename.sh
    –edit=True : edit variables. 編輯文章內的變數。輸入後當掃描到 SET var1=original 時,會等待使用者輸入新的 var1 變數值。

更新紀錄:隨著課程遇到越來越多不同的指令,慢慢加入新的並且更加精確的修正。

v0323:
add tempfile module.
change  “\r\n” to “\n”
“gawk” to “awk”, “” to ”

v0329:
change “rem” to “#”

v0402:
major update
new class: key_word_process:
__init__ : initialization
_add_var : add variable to the dictionary ‘var’, even edit it.
_get_var_value_line : return a line with variable setting.
_bat_to_sh_var : replace all variables stored in ‘var’ in the given sentence
pip_line_process : divide the pipe command in to two sentence and process with ‘parser’
parser : the parser, the return the replaced sentence.

now the scipt is able to process pipe(|) commands
add arguments :
-p : print out all the lines for inputfile
–help : print help information
–out=filename : specify the output filename
–edit=True : edit variables
add function :
main_process : construct ‘key_word_process’, call functions in ‘key_word_process’ and write file.
print_all_line : print all the line in the file include hidden characters
print_help : print help informations
v0405:
new keyword “Set”, equal to “set” (06a)
v0406:
solve the problem – the parser will not parse the second command of pipe(|) because of the space.
(Use lstrip to fix it)

程式做的事:
  • 修改換行符號 \r\n 為 \n 。
  • 辨認 SET var=* 的命令,轉為 var=* 或是使用者指定的新變數。
  • 消除 pause 指令( bash 無)。
  • 註解 REM 轉為#。
  • 刪除檔案 DEL 轉為 rm。
  • 列舉或是印出文字文件的 type 命令改為 cat。
  • gawk 改為 awk ,且雙引號 ” 改為 單引號 ‘ 。
程式碼:(未來有時間再解釋相關內容,不過註解寫滿多的應該不難讀 :P)
''' 
Script Name : DosToBash.py
* Minimum python version : 2.6 ( str.format() )
* Test python version : 2.7.10 64-bit on MacOSX 10.11 
Purpose : change DOS commands to bash command so that mac can run course example
Authur : CWSun @ NTU 2016.04
Mail : [email protected]
Description:
	This tool will find the specified words in "key_word_process.var" and replace them . 
	Then we will check some special syntax like "%filename%" to "$filename" .
==========
How to use : in command line, type:
$python DosToBash.py input_filename [arguments]
    arguments:
    input_filename : Required. 
    -p : print out all the lines for inputfile
    --help : print help information
    --out=filename : specify the output filename
    --edit=True : edit variables
'''
import io,os,sys,tempfile
code_version = "g20160406-1735"

class key_word_process():
    def __init__(self,edit=False):
        self.var={}
        self.edit_var=edit
        
    def _add_var(self,set_line):
        '''
        Input :
            (String)the line begin with "set var=value"
        Add key and value in to the dictionary "self.var"
        '''
        tmp_list=set_line.split(" ")[1].split("=")
        if self.edit_var==True:
            print "\nVariable \'{0}\' detected, the default value is\n{1}".format(tmp_list[0],tmp_list[1].rstrip('\n')) 
            newvalue=raw_input("Type new value here:")
            if newvalue != '':
                self.var[ tmp_list[0] ]=(newvalue+'\n')
            else:                         
                self.var[ tmp_list[0] ]=self._bat_to_sh_var(tmp_list[1])
        else:
            self.var[ tmp_list[0] ]=self._bat_to_sh_var(tmp_list[1])
    def _get_var_value_line(self,key):
        '''
        Use this function to get the key-value sentence
        Input : var_name (key)
        Output : a string in sentence (eg. "key=value\n")
        '''
        if not self.var.has_key(key):
            print "[Error] No variable named \"{0}\"".format(key)
            return (key+"\n")
        return str(key+"="+self.var[key])
    def _bat_to_sh_var(self,string):
        '''
        Input:the string list. eg. "string".split(" ")
        change %var% to $var
        '''
        for key in self.var.iterkeys():
            string = string.replace(str("%"+key+"%"),str("$"+key))            
                #string = string.replace(str("%"+key+"%\n"),str("$"+key+"\n"))
        return string #string
        
    def pip_line_process(self,line):
        line_list = line.split("|")
        new=[]
        for i in range(len(line_list) ):
            if i == 0:
                new.append(self.parser(line_list[i]))
            else:
                new.append(" "+self.parser(line_list[i].lstrip(" ")))
        return ( "|".join(new) )

    def parser(self,line):    
        tmp_line_list=line.split(" ")
        #Start to process the alteration
    
        #[first only] set --> add variable to var(dictionary)
        if tmp_line_list[0] in ["set","Set","SET"]:
            self._add_var(line)
            return self._get_var_value_line(tmp_line_list[1].split("=")[0])

        #[first only] pause --> ""
        elif tmp_line_list[0] in ["pause\n","PAUSE\n"]:
            return ""
        
        #[first only] REM --> #
        elif tmp_line_list[0] in ["REM","rem","Rem"]:
            tmp_line_list[0] = "#"
            return self._bat_to_sh_var(" ".join(tmp_line_list) )
        
        elif tmp_line_list[0] in ["REM\n","rem\n","Rem"]:
            return "#\n"
            
        #[first only] del --> rm
        elif tmp_line_list[0] in ["del","DEL","Del"]:
            tmp_line_list[0]="rm"
            return (" ".join(tmp_line_list))
        
        #[first only] type --> cat
        elif tmp_line_list[0] in ["type","TYPE","Type"]:
            tmp_line_list[0]="cat"
            return (" ".join(tmp_line_list))
        
        #[first only] gawk --> awk ; "" -> ''
        elif tmp_line_list[0]=="gawk":
            tmp_line_list = line.split("\"")
            tmp_line_list[0]=tmp_line_list[0].replace("gawk","awk")
            return self._bat_to_sh_var( ("\'".join(tmp_line_list)) )
        
        else: #eg. gmt command
            return self._bat_to_sh_var(line)
            


def main_process(infile,outfile,edit_var=False):
    '''
    Please open the file before calling this function !!
    '''
    go=key_word_process(edit=edit_var)
    outfile.write("# This file is automatically generated by DosToBash.py\n")
    for line in infile:
        sys.stdout.write('*') #Just for counting lines and show on the screen
        if line.find("|") != -1: # Use the pipe command in the line command
            outfile.write(go.pip_line_process(line) )
        else: # No pipe command in command (no "|")
            outfile.write(go.parser(line) )

def remove_r(InPath,tmpfile):
    with io.open(InPath,'rb') as infile:
        for line in infile:
            tmpfile.write(line.rstrip("\r\n")+'\n')
            
def print_all_line(InputFilePath):
    print "{:=^30}".format("Begin of the file")
    with io.open(InputFilePath,"rb") as InputFile:
        for line in InputFile:
            print repr(line)
    print "{:=^30}".format("End of the file")    
    
def print_help(mode=1):
    if mode == 0 : #help
        print "Use python DosToBash.py --help \nto get help"
        print "The script will exit now."
    elif mode == 1 : #syntax error
        print "\nHow to use :\npython DosToBash.py input_filename [arguments]"
        print "\n{0}".format("arguments:\n-p : print out all the lines for inputfile\n--help : print help information\n--out=filename : specify the output filename\n--edit=True : edit variables")

if __name__ == "__main__":
    edit_mode = False
    print "\n{:=^30}".format("==")
    print "Script Name : DosToBash.py"
    print "Purpose : change BATCH commands to BASH command so that Linux/Mac can run GMT2016 course example."
    print "Authur : CWSun @ NTU v{0}".format(code_version)
    '''
    arguments:
    input_filename : Required. 
    -p : print out all the lines for inputfile
    --help : print help information
    --out=filename : specify the output filename
    --edit=True : edit variables
    '''
    if len(sys.argv) == 1:
        print_help(1)
        tmp = raw_input("\nPress return to exit...\n")
        sys.exit(0)
        
    if not os.path.exists(sys.argv[1]): #File does not exist
        print "[Error] parameter 1 ({0}) is not a file.".format(sys.argv[1])
        sys.exit(0)
    AbspthOfFile=os.path.abspath(sys.argv[1])
    outputfilename=(os.path.splitext(AbspthOfFile)[0]+".sh")
    
    paras=sys.argv[2:]
    for p in paras:
        if p =="-p":
            print_all_line(AbspthOfFile)
            tmp = raw_input("\nPress return to exit...\n")
            sys.exit(0)
        elif p == "--help":
            print_help(1)
            tmp = raw_input("\nPress return to exit...\n")
            sys.exit(0)
                
        elif p.startswith("--out"):
            outputfilename=(os.path.join(os.path.dirname(AbspthOfFile),p.split("=")[1]))
        
        elif p.startswith("--edit"):
            if p.split("=")[1].title() == "True":    
                edit_mode = True
            elif p.split("=")[1].title() == "False":
                edit_mode = False
            else:
                print "[Error] you should use True/False in parameter \"--edit\"" 
                sys.exit(0)
        else:
            print "[Error] invalid argument {0}".format(p)
            print_help(0)
            sys.exit(0)
            
    print "\n{:=^30}".format("Creating tempfile")
    tempf = tempfile.TemporaryFile()
    print "\n{:=^30}".format("Removing \\r\\n")
    # Remove "\r\n" to avoid error in bash
    remove_r(AbspthOfFile,tempf)
    # Set the cursor to the head of the file
    tempf.seek(0)
    #begin main process
    print "\n{:=^30}".format("Begining main process")
    with io.open(outputfilename,"wb") as out_file:
        main_process(tempf,out_file,edit_mode)
    
    print "\n{:=^30}".format("Closing tempfile")
    tempf.close()

    print "\n{:=^30}".format(" Done ")
    print "processed file : "
    print "\n{0:<30}".format(outputfilename)
    print "\n{0:<30}".format("Notice : You should change os-dependent filepath on your own. (like d:\\files\)\n")
    tmp = raw_input("Press \"return to exit\"\n")
    

'''
Log :
    v0323:        
        add tempfile module.
        change  "\r\n" to "\n"
        "gawk" to "awk", "" to ''
    
    v0329:
        change "rem" to "#"
        
    v0402:
        major update 
        new class:key_word_process:
            __init__ : initialization
            _add_var : add variable to the dictionary 'var', even edit it.
            _get_var_value_line : return a line with variable setting.
            _bat_to_sh_var : replace all variables stored in 'var' in the given sentence
            pip_line_process : divide the pipe command in to two sentence and process with 'parser'
            parser : the parser, the return the replaced sentence.
            
        now the scipt is able to process pipe(|) commands
        add arguments :
            -p : print out all the lines for inputfile
            --help : print help information
            --out=filename : specify the output filename
            --edit=True : edit variables
        add function : 
            main_process : construct 'key_word_process', call functions in 'key_word_process' and write file.
            print_all_line : print all the line in the file include hidden characters
            print_help : print help informations
    v0405:
        new keyword "Set", equal to "set" (06a)
    v0406:
        solve the problem - the parser will not parse the second command of pipe(|) because of the space.
        (Use lstrip to fix it)
'''

 

請大家多多指教!!

請多多指教!

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料