shell - 把csh,sh或ksh语法的脚本相互转换的程序
把csh,sh或ksh语法的脚本相互转换的程序
2004-04-23 15:18 pm来自:Linux文档
现载:Www.8s8s.coM
地址:无名
把csh,sh或ksh语法的脚本相互转换的程序
这是我找到的一个csh2ksh converter.
你可以用一下看.
#!/usr/bin/nawk -f
#*TAG:35739 34:Apr 17 1996:0755:sh.d/csh2ksh:csh2ksh:
# csh2ksh 1.4
#************************************************************************
# Original by:Daniel Zepeda ([email protected])
# Enhanced version by:Brian Hiles ([email protected])
#
# This script will change a C-Shell script into a Korn Shell script.
# usage: csh2ksh <script.csh>
#
# Obviously, this script isn't going to pick up every little thing.
# You can do yourself a big favor by splitting multiple commands per line.
# Makes a half-hearted attempt to substitute multiple commands per line.
#************************************************************************
# glob (ksh N/I), hash (csh N/I), rehash, hashstat (N/I)
# get this to work on /usr/bin/vgrind, /usr/local/src/tcpdump-3.0/configure
# Each occurrence of a foreach, switch, while, if...then and else built-in
# must appear as the first word on its own input line.
# passthru!="ON" && /.../ {
# option to pass through/don't pass through unconvertable tokens
# Keep track of goto labels; if encountered, turn into a
# function, else make into an "exit" (special case "_bailout").
# Strip comments, place in buffer to be re-appended to $0 at EOR.
# It has to be assumed that syntactic units will be EOL, semicolon delimited
BEGIN {
#XXX need to save IFS? (always reinitialized to '
')
# Any functs below may be elim'd if script does not use feature.
# However, make sure to elim the respective alias and declaration!
#
prevcase=-1
if (ENVIRON["passthru"]!="") #XXX
# flag to pass through unsubstitutable tokens to output
print "passthru=" (passthru="ON") >"/dev/tty"
if (ENVIRON["casualvars"]!="")
# flag to suppress the assumption of variables being arrays
print "casualvars=" (casualvars="ON") >"/dev/tty"
if (ENVIRON["nopreamble"]!="")
# flag to suppress the output of the env preamble code
print "nopreamble=" (nopreamble="ON") >"/dev/tty"
if (nopreamble!="ON")
print "#!ksh
"
"set -A argv '' "$@"
"
"home=$HOME mail=$MAIL prompt=$PS1 shell=$SHELL
"
"term=$TERM user=$USER _IFS=$IFS IFS=:
"
"set -A cdpath '' $CDPATH; set -A path '' $PATH
"
"IFS=" $_IFS" alias chdir=cd login='exec /bin/login'
"
"nice='nice ' rehash='PATH=$PATH' unhash='set +o traceall'
"
"set -o nounset
"
"#
## any of the following functions+attributes and/or aliases
"
"## may be eliminated if that feature is not used in this script
#
"
"# avail to serve the usual purpose of a label at or near EOF
"
"function _bailout
"
"{ exit
}
"
"# directory stack: nec to maintain correct dirstack upon chdir
"
"alias _cd=cd; typeset -fx _cd
"
"function _cd
"
"{ # make top of directory stack cwd
"
" set -o noglob +o nounset
"
" cd "$@" && set +A _dirstack ~+/
}
"
"# emulate the csh implementation of "limit"
"
"alias limit=_limit; typeset -fx _limit
"
"function _limit
"
"{ eval ulimit -a ${1:+| "
"egrep "^(nofiles\()?${1#cpu}" ||
"
" print -ru2 limit -- No such limit}
}
"
"# emulate the csh implementation of "shift"
"
"alias shift=_shift; typeset -fx _shift
"
"function _shift
"
"{ if [[ ${1-argv} = argv ]]
"
" then trap 'set -- "${argv[@]}"
"
" shift 2
"
" set -A argv "" "$@"' EXIT
"
" else typeset _varx=$1
"
" eval set -- ""${$1[@]?}""
"
" shift
"
" set -A $_varx "$@"
"
" fi
}
"
"# emulate the csh implementation of "source"
"
"typeset -fx _source
"
"function _source
"
"{ if file ${1:?source -- Too few arguments} 2>&- |
"
" grep -s '/bin/k?sh'
"
" then trap '. "$@"' EXIT
"
" else print -u2 cannot source "$1" -- not k/sh script
"
" exit 1
"
" fi
}
"
"# directory stack: emulate the csh implementation of "dirs"
"
"typeset -fx dirs
"
"function dirs
"
"{ # display directory stack
"
" set -o noglob +o nounset
"
" typeset dir
"
" (($#>=2)) &&
"
" { print -ru2 'dirs: Too many arguments'
"
" return 1
"
" }
"
" if [[ $1 = -l ]]
"
" then for dir in ${_dirstack[*]:-$PWD/}
"
" do print -nr -- "${dir%/} "
"
" done
"
" else for dir in ${_dirstack[*]:-$PWD/}
"
" do dir=${dir#$HOME/}
"
" case $dir in
"
" ('') print -nr -- '~ ' ;;
"
" (/*) print -nr -- "${dir%/} " ;;
"
" (*) print -nr -- "~/${dir%/} " ;;
"
" esac
"
" done
"
" fi
"
" print
}
"
"# directory stack: emulate the csh implementation of "popd"
"
"typeset -fx popd
"
"function popd
"
"{ # cd to and/or delete stack entry
"
" set -o noglob +o nounset
"
" if ((!$#))
"
" then # pop directory off the stack, cd to new top
"
" if cd ${_dirstack[1]:?Directory stack empty.}
"
" then unset _dirstack[0]
"
" set -A _dirstack ${_dirstack[*]}
"
" dirs
"
" else unset _dirstack[0]
"
" set -A _dirstack ${_dirstack[*]}
"
" return 1
"
" fi
"
" elif [[ $# = 1 && $1 = ++([0-9]) ]]
"
" then # case of popd +n: delete nth dir from stack
"
" typeset -i ndir
"
" set ${1#+}
"
" # uncomment to use last element if param exceeds permissible:
"
" #let "$1 > (ndir=${#_dirstack[*]}-1)" && set -- $ndir
"
" let "$1 > ${#_dirstack[*]}-1" &&
"
" { print -u2 'popd: Directory stack not that deep.'
"
" return 1
"
" }
"
" (($1<=0)) &&
"
" { print -u2 'popd: Bad directory.'
"
" return 1
"
" }
"
" unset _dirstack[$1]
"
" set -A _dirstack ${_dirstack[*]}
"
" dirs
"
" else print -u2 'popd: Too many arguments.'
"
" return 1
"
" fi
}
"
"# directory stack: emulate the csh implementation of "pushd"
"
"typeset -fx pushd
"
"function pushd
"
"{ # make new top of stack cwd
"
" set -o noglob +o nounset
"
" if ((!$#))
"
" then # case of pushd without args; swap top two directories
"
" if cd ${_dirstack[1]:?No other directory.} 2>&-
"
" then set +A _dirstack ${_dirstack[1]} ${_dirstack[0]}
"
" dirs
"
" else print -ru2
"
" "pushd: ${_dirstack[1]}: No such file or directory."
"
" return 1
"
" fi
"
" elif [[ $# = 1 && $1 = ++([0-9]) ]]
"
" then # case of pushd +n: rotate left n times directory stack
"
" typeset -i ndir nrot=${1#+}
"
" typeset firstdir
"
" # uncomment to use last element if param exceeds permissible:
"
" #let "nrot+1>(ndir=${#_dirstack[*]})" && let nrot=ndir-1
"
" let "nrot > (ndir=${#_dirstack[*]}-1)" &&
"
" { print -ru2 'pushd: Directory stack not that deep.'
"
" return 1
"
" }
"
" ((nrot<=0)) &&
"
" { print -ru2 'pushd: +0: No such file or directory.'
"
" return 1
"
" }
"
" while let '(nrot-=1)>=0'
"
" do firstdir=${_dirstack[0]}
"
" unset _dirstack[0]
"
" set -A _dirstack ${_dirstack[*]} $firstdir
"
" done
"
" cd ${_dirstack[0]} && dirs
"
" elif (($#==1))
"
" then # one argument is directory to push
"
" if cd ${1:?No such file or directory.} 2>&-
"
" then set -A _dirstack ~+/ ${_dirstack[*]:-$OLDPWD/}
"
" dirs
"
" else print -ru2 "pushd: $1: No such file or directory."
"
" return 1
"
" fi
"
" else print -ru2 'pushd: Too many arguments.'
"
" return 1
"
" fi
}
"
"LINENO=0"
}
{donescan="OFF" }# like a "next" command, except ...
/^[ ]*($|#)/ {# empty line or comment
# Suppress newlines between case patterns, so that
# introduced escaped newlines will act appropriately.
if (prevcase==NR-1)
prevcase+=1
else
print
next
}
{gsub("[ ]+;", ";")# so that "command ;" !~ /command[ ]/
if ($0!~/[ ]+/)
sub("[ ]+$", "")
sub(";$", "")
}
/$/ {# normalize and convert variable syntax
#XXX must appear before `.*`
gsub("${?", "${#"); gsub("$?", "$#")
gsub("${?#?[A-Za-z_][A-Za-z_0-9]+([.*]])?}?", "!<!&!>!")
gsub("$[1-9]", "!<!&!>!")
#
# delimit variable with braces, if none exist:
gsub("!>![", "[")
if (gsub("]", "&}"))
gsub("]}}", "]}")
if (gsub("!<!$", "&{"))
gsub("!<!${{", "!<!${")
if (gsub("!>!", "}&"))
gsub("}}!>!", "}!>!")
#
# add default "[@]" array indices, if none exist:
gsub("[*]", "[@]")# [*] -> [@]
# turn positional parameters into argv array r-values (for robustness)
if (casualvars!="ON")
if (gsub("${[1-9]}!>!", "${argv[!#!&!#!"))
{gsub("!#!${", "")
gsub("}!>!!#!", "]}")
}
if (casualvars!="ON")
if (gsub("}!>!", "[@]&"))
gsub("[@][@]", "[@]")# ${var} -> ${var[@]}
gsub("}[", "[")# ${var}[ -> ${var[
#
# substitute special variables:
gsub("$#0", "${0:+1}")# special case: $?0 must be in ((...))
gsub("${status[@]}", "$?")
gsub("${child[@]}", "$!")
gsub("${cwd[@]}", "${PWD}")
#
# miscellaneous:
gsub("![<>]!", "")
#XXXgsub(":g[ehrtq]", "")# specifiers won't work on array elmts
gsub(":q", "")# implement instead using dquotes!
gsub("}:e", "##*.}")
gsub("}:h", "%/*}")
gsub("}:r", "%.*}")
gsub("}:t", "##*/}")
}
/(^|[ ;&|])set[ ]/ {# set command syntax
#XXX $0 alert! (must then be EOL)
# "set var = ( ... )"
# -xor-
# "set var = value" -or- "set var=value" -or- "set var"
# "set echo/ignoreeof/noclobber/noglob/nonomatch/notify/verbose"
sub("(^|[ ]+)set[ ]+", "")
if (gsub("[ ]+=", "="))
gsub("=[ ]+", "=")
if ($0~")($|[ ])")
{# "set var=(...)" -> "set -A var ... ;"
gsub("[^ ]+=(", " ; set -A &")
gsub("=(", " ")
gsub(")", " ; ")
gsub("set -A argv[^;]*", "& && set -- "${argv[@]}"")
sub("^ ; ", "")
}
else
{#XXX quoted text may get changed!!
$0=" " $0 " "
gsub("[ ]+", " ")
gsub(" [A-Za-z_0-9]+ ", " &= ")
gsub(" +=", "=")
sub("^ +", "") #XXX
print "DEBUG: |" $0 "|" >"/dev/tty"
# "set echo/ignoreeof/noclobber/noglob/nonomatch/notify/verbose"
sub("echo=", ";set -o xtrace ;")
sub("ignoreeof=", ";set -o ignoreeof ;")
sub("noglob=", ";set -o noglob ;")
sub("nonomatch=", ";set -o verbose ;")
sub("verbose=", ";set -o verbose ;")
}
}
/(^|[ ;&|])source[ ]/ {# source script
#XXX either this or function _source defined above!
if (nopreamble=="ON")
gsub("source[ ]+", ". ")
}
/(^|[ ;&|])echo($|[ ])/ {# echo -> print
gsub("echo[ ]*", "print -- ")
sub("print -- -n[ ]", "print -n -- ")
}
/(^|[ ;&|])foreach[ ].*(.*)/ {# foreach -> for ... do
# warning! (.*) must appear on the same line
#XXX must appear before (.*) part
#XXX $2 alert! (foreach must then be BOL)
gsub("foreach", "for ")
sub($2, $2 " in ")
gsub("(", "")
gsub(")", " ; do ")
}
/(^|[ ;&|])while[ ]+(.*)/ {# while -> while ... do
# warning! (.*) must appear on the same line
gsub("(", "")
gsub(")", " ; do ")
}
/(^|[ ;&|])goto[ ]/ {# goto -> funct call (see docs)
#XXX must appear before "case" part
#XXX can goto's be right semi delimited ?
# _Back_ reference(s) and/or _one_ skip-to-EOF
# label ("_bailout") are the only ones permitted.
gsub("goto[ ]+_?", "_")
label[$1]=$1
}
/(^|[ ;&|])case[ ].*/ {# case -> case-pattern
# warning! must appear rightmost
#XXX must appear before label part
if (prevcase!=NR-1)
gsub("case[ ]+", "")
else
gsub("case[ ]+", "|")
gsub(":", "")
# for multiple "case" statements having appeared on same line: #XXX
gsub("\[ ]+|?", " | ")
prevcase=NR
}
/(^|[ ;&|])switch[ ]+(.*)/ {# switch -> case ... {
# warning! must not appear with another (.*)
#XXX (.*) must appear on the same line
gsub("switch[ ]+", "case ")
gsub("(", " ")
gsub(")", " { ")
}
/(^|[ ;&|])breaksw$/ {# breaksw -> ;;
# warning! you _must_ use the (optional!) "breaksw" command
#XXX can this be right semi delimited?
gsub("breaksw", " ;; ")
}
/(^|[ ;&|])endsw$/ {# endsw -> esac
#XXX can this be right semi delimited ?
gsub("endsw", "}")
}
/(^|[ ;&|])alias[ ]/ {# alias syntax
#XXX $0 alert! (must then be EOL)
# unalias is meant to pass through
# "csh: alias var 1 2" -> "alias var (1 2)"
sub("alias[ ]+[A-Za-z_0-9]+[ ]", "&!<!") #XXX
sub(" !<!", "='")
$0=$0 "'"
}
/(^|[ ;&|])setenv($|[ ])/ {# setenv -> export
#XXX $2 alert! (must then be BOL)
#XXX $0 alert! (must then be EOL)
#XXX can this be right semi delimited ?
gsub("setenv", "export ")
if ($2!="")
{sub($2, $2 "=")
sub("=[ ]*", "='")
$0=$0 "'"
}
}
/(^|[ ;&|])end$/ {# end -> done
#XXX can this be right semi delimited ?
gsub("end", "done")
}
/(^|[ ;&|])endif$/ {# endif -> fi
# csh: must be the first word on the line
#XXX can this be right semi delimited ?
gsub("endif", "fi")
}
/(^|[ ;&|])(else[ ]+)?if[ ]*(/ {# else if -> elif
# csh: must be the first word on the line
#XXX must appear before "if" part
gsub("else[ ]+if[ ]*", "elif ")
}
/(^|[ ;&|])(el)?if[ ]*(.*)/ {# (else)if/then syntax
# warning! (.*) must appear on the same line
#XXX except when their is no "then" part!
#XXX $0 alert! (must then be EOL) ??
if ($0~/)[ ]+then($|[ ])/)
{gsub(")[ ]+then($|[ ])", ") ; then ")
}
else
{# if ... syntax -> ... &&
gsub("if[ ]+(", "( ")
gsub(")[ ]+", ") && ")
}
}
/(.*)/ {# expression syntax
# warning! (.*) part must appear on the same line
#XXX need to convert to ((...)) when applicable
#gsub("&&", " ]] &&
[[ ")
#gsub("||", " ]] ||
[[ ")
#
# (...)grouping
# ~one's complement
# !logicalnegation
# * / %multiplication,division, remainder (These are
# right associative, which can lead to
# unexpected results. Group combinations
# explicitly withparentheses.)
# + -addition, subtraction (also right associative)
# << >>bitwiseshift left, bitwise shift right
# < > <= >=less than, greater than, less than or equal
# to, greater than or equal to
# == != =~ !~equal to, not equal to,filename-substitution
# patternmatch (described below), filename-
# substitution pattern mismatch
# &bitwiseAND
# ^bitwiseXOR (exclusive or)
# |bitwiseinclusive OR
# &&logicalAND
# ||logicalOR
#
#XXX change into ((...)) or [[ ... ]], where appropriate.
gsub("(", " [[ ")
gsub(")", " ]] ")
gsub("==", "=")
gsub("=~", "=")
gsub("!~", "!=")
gsub("<=", "-le")
gsub(">=", "-ge")
gsub(">", "-lt")
gsub("<", "-gt")
}
/[ ="']`.*`/ {# command substitution syntax
#XXX must be after expression part
#XXX do csh bquotes need to both be on the same line?
while (sub("`", "$("))
sub("`", ")")
}
/$</ {# $< -> read ...
#XXX must appear after expression syntax
#XXX set var = ($<) ??
gsub("$<", "$(line)")
#gsub("=$<", "")
#gsub($1, "read " $1)
}
/(^|[ ;&|])unalias[ ]/ {# unalias syntax
#XXX unalias with no arguments is meant to pass through
#XXX will choke on escaped file substitution words!
gsub("*", ".*", $2)
gsub("?", ".", $2)
gsub("unalias[ ]+", "unalias $(typeset +|grep '^" $2 "$')")
}
/(^|[ ;&|])unset[ ]/ {# unset syntax
#XXX must appear after `.*` and expression parts
#XXX will choke on escaped file substitution words!
gsub("*", ".*", $2)
gsub("?", ".", $2)
gsub("unset[ ]", "unset $(typeset +|grep '^" $2 "$')")
}
#XXX
/XXX(^|[ ;&|)@($|[ ])/ {# @ -> let
#XXX must appear after expresssion part
#XXX does "@" have a significance to a "nawk" r.e. ??
if ($2!="")
{sub("@[ ]+", "(( ")
$0=$0 " ))"
}
else
{sub("@", "typeset -")
}
}
/(^|[ ;&|])onintr($|[ ])/ {# interrupt trapping
#XXX $0 alert (must then be EOL!)
if ($0~/onintr$/)
{$0="trap -"
}
else if ($0~/[ ]-$/)
{$0="trap ''"
}
else
{gsub("onintr[ ]+", "trap _")
$0=$0 " INT"
}
}
/^[ ]*default:$/ {# default: -> *)
#XXX must appear before "label" part
gsub("default:", "*)")
}
/(^|[ ;&|])[A-Za-z_][A-Za-z_0-9]*:$/ {# goto label -> function definition
#XXX $0 alert! (must then be EOL)
# The special label "_bailout" should be used
# for the usual purpose of breaking to EOF.
if ($0~/(^|[ ]+)_?bailout:$/)
next# already defined as function above
sub("[A-Za-z_0-9]+:", "_&")
sub(":", " () { eval ${1:+trap "set -- $@; set -A argv "$@"" EXIT}")
}
/>&?(?!)?/ {# redirection operators syntax
# > >! >& >&!
# >> >>& >>! >>&!
gsub(">>&", " 2!#!&1 !#!>")
gsub(">&", " 2>&1 >")
gsub("!#!", ">")
gsub(">(\)?!", ">|")
gsub(">>|", ">>")# because ">>|" is ksh syntax error
}
{gsub(" +", " ")# strip redundant spaces
#XXX this should be subsumed by escnl rejoined in prior pass
if ($0~/[&|][ ]+$/)
# "|", "||", "&&" operators don't need escaped newline
$0=substr($0, 1, length($0)-2)
sub(" ", " ")
sub("[ ]+$", "")# strip any trailing whitespace
sub("[^;];$", "")# strip any trailing semicolon
sub("[^;];$", "")# and do it again (#XXXtry "@" feature)
if (!prevcase || prevcase==NR-1)
# append right paren delimiting multi-line case patterns
$0=")
" $0
print
#printf "%2d,%2d: %s
", NR, prevcase, $0
}
END {
#XXX undefined hash print order!
# for every "onintr" label turned into a function...
for (key in label)
if (key!="_bailout")
print "}; " label[key]
}
偶觉得不太会有这种自动转换程序吧,其实自己手工转换一下,正好熟悉几种shell的区别,乐事也