#!/usr/bin/env python3 """ July 18, 2008, Dr. Brian Fristensky, University of Manitoba csh2sh.py - convert csh scripts to sh script. The input filename should be in the form x.csh, and the output file will be x.sh WARNING: This script only does some very crude substitutions. Code generated by this script should be considered as a starting point for manual translation to sh. Version 11/15/09 Synopsis: csh2sh.py infile infile - csh script @modified: May 26 2010 @author: Dale Hamel @contact: umhameld@cc.umanitoba.ca """ import sys import os import re import shutil import sys blib = os.environ.get("BIRCHPYLIB") sys.path.append(blib) from birchlib import Birchmod from birchlib import Argument PROGRAM = "csh2sh.py: " USAGE = "\n\t USAGE: csh2sh.py infile {infile must be csh script}" BM = Birchmod(PROGRAM, USAGE) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Parameters: "Wrapper class for command line parameters" def __init__(self): """ Initializes arguments: NFN="" IFN="" OFN="" Then calls read_args() to fill in their values from command line """ self.IFN = "" self.OFN = "" self.read_args() def read_args(self): """ Read command line arguments into a Parameter object """ infile = Argument("", str, BM) infile.set_position(1) try: self.IFN = infile.fetch() self.OFN = self.IFN if self.OFN.endswith('.csh'): self.OFN = self.OFN[0:-4] self.OFN = self.OFN + '.sh' except: BM.printusage() # I = 2 # while (I < numargs) : # # This code is here as a placeholder for # # future command line switches # if sys.argv[I] == "-dummy1" : # I = I + 1 # if I < numargs : # I = I + 1 # elif sys.argv[I] == "-dummy2" : # I = I + 1 # if I < numargs : # I = I + 1 # else : # P.OFN = sys.argv[I] # I = numargs # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class scriptfile: "Contents of the file" def __init__(self): """ Initializes arguments: text="" """ self.text = "" def read_file(self, IFN): """ @param IFN: name of input file @type IFN: str """ infile = open(IFN, 'r') self.text = infile.read() infile.close() return def write_file(self, OFN): """ @param OFN: name of ouput file @type OFN:str """ outfile = open(OFN, 'w') outfile.write(self.text) outfile.close() return # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def convert(script): """Iterate through the script replacing csh syntax with sh syntax. """ script.text = re.sub('#!/bin/csh', '#!/bin/sh', script.text) # arguments script.text = re.sub('\$#argv', '$#', script.text) script.text = re.sub('\$argv', '$*', script.text) # We still need to handle the usage: $argv[n] # Convert $home, $path to $HOME, $PATH script.text = re.sub('\$home', '$HOME', script.text) script.text = re.sub('\$path', '$PATH', script.text) #------ File name manipulations ----------- # Basename: $FILE:t exp1 = '(\$)(.+)(:t)' exp2 = '`basename \g<1>\g<2>`' script.text = re.sub(exp1, exp2, script.text) # File extension: $FILE:e exp1 = '(\$)(.+)(:e)' exp2 = '\g<1>{\g<2>##*.}' script.text = re.sub(exp1, exp2, script.text) # Filename minus file extension: $FILE:r exp1 = '(\$)(.+)(:r)' exp2 = '\g<1>{\g<2>%.*}' script.text = re.sub(exp1, exp2, script.text) # ---------- Flow of control statements --------------------- # if then exp1 = '([\t ]*)(if[\t ]+)(.+)([\t ]+then)' exp2 = '\g<1>if [ \g<3> ]\n\g<1>\tthen' script.text = re.sub(exp1, exp2, script.text) exp1 = '(if \[)([\t ]+)(\()(.*)(\))([\t ]*)(\])' exp2 = 'if [ \g<4> ]' script.text = re.sub(exp1, exp2, script.text) script.text = re.sub('endif', 'fi', script.text) # set, setenv exp1 = '(set[\t ]+)(\S+)([\t ]+=[\t ]+)(\()(\s)(.*)(\s)(\))' exp2 = '\g<1>\g<2>\g<3>"\g<6>"' script.text = re.sub(exp1, exp2, script.text) script.text = re.sub('(set[\t ]+)(\S+)([\t ]+=[\t ]+)', '\g<2>=', script.text) script.text = re.sub('([\t ]*)(setenv[\t ]+)(\S+)([\t ]+)(\S+)', '\g<1>\g<3>=\g<5>\n\g<1>export \g<3>', script.text) # switch script.text = re.sub('(switch[\t ]+\()(\S+)([\t ]*\)[\t ]*)', 'case \g<2> in', script.text) script.text = re.sub('(case[\t ]+)(\S+)([\t ]*\:[\t ]*)', '\g<2>)', script.text) script.text = re.sub('breaksw', ';;', script.text) script.text = re.sub('default:', '*)', script.text) script.text = re.sub('endsw', 'esac', script.text) # while exp1 = '(while[\t ]+)(\()(.*)(\)[\t ]*\n)' exp2 = 'while [ \g<3> ]\n\tdo\n' script.text = re.sub(exp1, exp2, script.text) script.text = re.sub('(\n[\t ]*)(end)', '\g<1>done', script.text) # foreach #this doesn't seem to work and I can't figure out why. exp1 = '([\t ]*)(foreach[\t ]+)(\S+)([\t ]+)(.*)' exp2 = '\g<1>for \g<3> in \g<5>\n\g<1> do\n' script.text = re.sub(exp1, exp2, script.text) # Also replace parentheses with double quotes, for lists in a for expression exp1 = '(for[\t ]+\S+[\t ]+in[\t ])(\()(.*)(\))' exp2 = '\g<1>"\g<3>"' script.text = re.sub(exp1, exp2, script.text) #Lists exp1 = re.compile('(\S+=)(\()(.*?)(\))', re.DOTALL | re.MULTILINE) exp2 = '\g<1>"\g<3>"' script.text = re.sub(exp1, exp2, script.text, re.DOTALL | re.MULTILINE) # boolean tests exp1 = '(\$\{\?)(\S+)(\})' exp2 = '! -z "$\g<2>"' script.text = re.sub(exp1, exp2, script.text) return #======================== MAIN PROCEDURE ========================== def main(): """ Called when not in documentation mode. """ P = Parameters () # Read the csh file script = scriptfile() script.read_file(P.IFN) # Replace csh syntax with sh syntax. convert(script) # WARNING: this is currently a very simple-minded replacement. script.write_file(P.OFN) os.chmod(P.OFN, 0o755) if (BM.documentor() or "-test" in sys.argv): pass else: main()