home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / te < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  12.1 KB  |  389 lines

  1. #!/bin/ksh
  2. # @(#) te.ksh,where.ksh 2.1.1 97/07/20
  3. # 92/08/31 John H. DuBois III (john@armory.com)
  4. # 92/09/10 added -p option to whence
  5. # 92/10/16 Allow multiple ,-separated targets; added help
  6. # 92/10/21 Added {}
  7. # 93/08/02 Changed name to te to avoid conflict with to
  8. # 94/03/08 Added -c option
  9. # 94/06/29 Added -xpt.  Fixed bug in {} processing which caused all target
  10. #          executables to be substituted for {} as a single word.
  11. # 95/04/23 Added TECMD env var, n option, & rcfile processing
  12. # 95/05/17 Change window title if appropriate
  13. # 96/08/24 Let capital letters turn off options.  Merged te and where.
  14. #          Added aL options.
  15. # 96/09/03 Do not search for absolute paths in $PATH.
  16. # 97/07/20 2.1.1 In 'where' mode, print each match as it is found rather than
  17. #          storing in an array, to avoid 1024-element limit.
  18.  
  19. # todo: option to cd to directory that 1st file is found in before running
  20. # command.
  21.  
  22. name=${0##*/}
  23. iUsage="$name [-aAeEfFhlLnsStTvVwW] [-p<path>]"
  24. Usage=\
  25. "Usage: 
  26. $iUsage target[,target,...] [cmd [arg ...]]
  27. $iUsage -c \"cmd [arg ...]\" target [target ...]"
  28.  
  29. # Only take TECMD from the environment
  30. Debug=false Test=false VERBOSE= notVERBOSE=false Readrc=true CmdGiven=false
  31. ALL= notALL=false NOTITLE= notNOTITLE=false ANYFILE= notANYFILE=false
  32. SYMLINKS= notSYMLINKS=false EXACT= notEXACT=false SHELLPAT= notSHELLPAT=false
  33. listTargets=false where=false types=
  34. rcFile=.terc
  35. searchPath=$PATH
  36.  
  37. if [ "$name" = where ]; then
  38.     listTargets=true SHELLPAT=1 Readrc=false where=true
  39. fi
  40.  
  41. while getopts :aAc:eEfFhlLnp:sStTvVwWx opt; do
  42.     case $opt in
  43.     h)
  44.     echo \
  45. "$name: execute commands on commands.
  46. $Usage
  47. Each target is searched for as a command in \$PATH and expanded into its
  48. full filename.  command [arg ...] is then executed with the list of
  49. filenames as additional arguments.  Targets given with absolute paths are
  50. operated on directly without searching for them in \$PATH (as is the behaviour
  51. when a program name is given to the shell to be executed).
  52. If one of the arguments is \"{}\", it is replaced with the list of
  53. filenames and the filenames are not passed as additional arguments.
  54. Targets can be specified either as a comma-separated list followed by the
  55. command and its optional initial arguments, or if the command is given with -c,
  56. as a list of separate arguments following the command (which in this case must
  57. be quoted to make it a single argument if it includes initial arguments to the
  58. command).  
  59. If the environment variable TECMD is set, it provides a default command and
  60. optional initial arguments to it to run if no command is specified (if only
  61. one argument is given and -c is not given).  TECMD may also be assigned a value
  62. in the configuration file described below.
  63. If the environment variables WINTITLE, DISPLAY, and EDITOR are set, and the
  64. command to be run is the same as the value of EDITOR, an xterm escape sequence
  65. is sent to change the window title to the name of the files being edited,
  66. followed by the value of WINTITLE in parentheses.  After editing is completed,
  67. another sequence is sent to change the window title back to the value of
  68. WINTITLE by itself.
  69.  
  70. Options:
  71. Some of the following options can be set in a configuration file named
  72. \"$rcFile\", which may be in the invoking user's home directory or in the
  73. directory specified by the environment variable UHOME (if both exist,
  74. assignments in the former take precedence).  In this file, values are assigned
  75. to variables in shell style, e.g. \"VARNAME=value\".  To set an option that
  76. does not take a value, use \"VARNAME=1\".  Options given in the configuration
  77. files are overridden by those given on the command line.  Use the upper case
  78. version of a Boolean (on or off) option letter to unset it.  Variable names are
  79. given in parentheses following option descriptions.
  80. Example contents of a $rcFile file:
  81. TECMD=\"vi -c'set ts=4'\"
  82. If this program is invoked as \"where\", the T, s, and n options are turned on.
  83. -a: Execute the command on every instance of the target that occurs in the
  84.     search path, instead of just the first occurance.  (ALL)
  85. -s: Treat filenames as unanchored ksh shell patterns.  This causes e.g. the
  86.     pattern \"bar@(ba|fi)z\" to select filenames that contain the string barbaz
  87.     or barfiz.  See the regexp(M) man page for a description of ksh filename
  88.     patterns.  Patterns are surrounded by implicit '*' characters, causing them
  89.     to be unanchored.  This can be overridden by using '^' and '$' to force a
  90.     match to start at the beginning and end at the end of a filename
  91.     respectively.  Characters that are special to the shell must generally
  92.     be protected from the shell by surrounding them with quotes.  (SHELLPAT)
  93. -e: Used with -s, finds exact (complete) matches only; equivalent to putting ^
  94.     and $ at the start and end of each pattern.  (EXACT)
  95. -f: Find any matching regular file in the search path, regardless of whether it
  96.     is executable or not.  (ANYFILE)
  97. -l: Also find any matching symlink in the search path, regardless of whether
  98.     the file it points to exists or is executable.  (SYMLINKS)
  99. -p<path>: Use <path> as the search path instead of using the value of the PATH
  100.     variable.
  101. -h: Print this help.
  102. -n: Do not read the $rcFile file.
  103. -w: Do not send an xterm title escape sequence.  (NOTITLE)
  104. -v: Print the command before it is run.  (VERBOSE)
  105. -t: Print the command that would be executed, but do not run it.
  106. -T: Print a list of all matching target files, without doing anything to them.
  107.     This turns on the a option."
  108.     exit 0
  109.     ;;
  110.     c)
  111.     Cmd=$OPTARG
  112.     CmdGiven=true
  113.     ;;
  114.     x)    Debug=true;;
  115.     w)    NOTITLE=1;;
  116.     W)    notNOTITLE=true;;
  117.     n)    Readrc=false;;
  118.     t)    Test=true;;
  119.     T)    listTargets=true;;
  120.     v)    VERBOSE=1;;
  121.     V)    notVERBOSE=true;;
  122.     p)    searchPath=$OPTARG;;
  123.     f)    ANYFILE=1;;
  124.     F)    notANYFILE=true;;
  125.     e)    EXACT=1;;
  126.     E)    notEXACT=true;;
  127.     s)    SHELLPAT=1;;
  128.     S)    notSHELLPAT=true;;
  129.     l)    SYMLINKS=1;;
  130.     L)    notSYMLINKS=true;;
  131.     a)    ALL=1;;
  132.     A)
  133.     notALL=true;;
  134.     +?)
  135.     print -ru2 -- "$name: options should not be preceded by a '+'."
  136.     exit 1
  137.     ;;
  138.     :) 
  139.     print -r -u2 -- \
  140.     "$name: Option '$OPTARG' requires a value.  Use -h for help."
  141.     exit 1
  142.     ;;
  143.     :) 
  144.     print -r -u2 -- \
  145.     "$name: Option '$OPTARG' requires a value.  Use -h for help."
  146.     exit 1
  147.     ;;
  148.     ?) 
  149.     print -ru2 -- "$name: $OPTARG: bad option.  Use -h for help."
  150.     exit 1
  151.     ;;
  152.     esac
  153. done
  154.  
  155. # remove args that were options
  156. let OPTIND=OPTIND-1
  157. shift $OPTIND
  158.  
  159. function CheckPat {
  160.     typeset file pattern=$1 t
  161.     typeset -i ret=0
  162.  
  163.     [ -n "$SHELLPAT" ] && set -- $pattern || set -- "$pattern"
  164.     for file; do
  165.     if [ -x "$file" -a -f "$file" ]; then
  166.         if $listTargets; then
  167.         print "$file"
  168.         else
  169.         Files[type_i]=$file
  170.         [ -z "$ALL" ] && return
  171.         fi
  172.         ret=1
  173.         let type_i+=1
  174.     else
  175.         for t in $types; do
  176.         if [ -$t "$file" ]; then
  177.             if $listTargets; then
  178.             print "$file"
  179.             else
  180.             Files[type_i]=$file
  181.             [ -z "$ALL" ] && return
  182.             fi
  183.             ret=1
  184.             let type_i+=1
  185.         fi
  186.         done
  187.     fi
  188.     done
  189.     return $ret
  190. }
  191.  
  192. # Usage: PathSearch pattern
  193. # Sets Files[] to all files in Paths[] that match the pattern
  194. # type_i is set to the number of matches, which is the number of elements
  195. # put in Files[] if listTargets is false.
  196. typeset -i type_i
  197. function PathSearch {
  198.     typeset arg=$1 found=false PathElem
  199.  
  200.     set +f            # make sure filename globbing is on
  201.     unset Files
  202.     type_i=0
  203.     if [ -n "$SHELLPAT" -a -z "$EXACT" ]; then
  204.     # Discard anchor chars if given, since they are not real metachars
  205.     if [[ "$arg" = ^* ]]; then
  206.         arg=${arg#?}    
  207.     else
  208.         arg="*$arg"    # Pattern is not anchored at start
  209.     fi
  210.     if [[ "$arg" = *\$ ]]; then
  211.         arg=${arg%?}
  212.     else
  213.         arg="$arg*"    # Pattern is not anchored at end
  214.     fi
  215.     fi
  216.     if [[ "$arg" = /* ]]; then
  217.     CheckPat "$arg"
  218.     else
  219.     # Find all pattern matches that are executable regular files.
  220.     for PathElem in "${Paths[@]}"; do
  221.         CheckPat "$PathElem/$arg"
  222.     done
  223.     fi
  224. }
  225.  
  226. # This code must come after arg processing because until args are processed
  227. # we do not know if we should read the rcfile or not.
  228. rcFile=$HOME/$rcFile
  229. # Let TECMD in the environment override rcfile
  230. oTECMD=$TECMD
  231. $Readrc && [ -f "$rcFile" ] && . $rcFile
  232. [ -n "$oTECMD" ] && TECMD=$oTECMD
  233. [ -z "$Cmd" -a -n "$TECMD" ] && Cmd=$TECMD
  234.  
  235. $listTargets && ALL=1
  236. $notNOTITLE && NOTITLE=
  237. $notVERBOSE && VERBOSE=
  238. $notALL && ALL=
  239. $notANYFILE && ANYFILE=
  240. $notSYMLINKS && SYMLINKS=
  241. $notSHELLPAT && SHELLPAT=
  242. $notEXACT && EXACT=
  243. [ -z "$SHELLPAT" ] && EXACT=
  244. [ -n "$SYMLINKS" ] && types=L
  245. [ -n "$ANYFILE" ] && types="$types f"
  246.  
  247. # $Cmd is now either a command given with -c or a default command (if any).
  248. # If a command was given with -c, each remaining arg is a target.
  249. # Otherwise, $1 is a comma-separated list of targets; any further arguments
  250. # are the command and its args.
  251.  
  252. typeset -i MinArgs
  253. # If we have a default or -c command, need only one arg (target).
  254. # Otherwise, need at least two (list of targets and command).
  255. [ "$name" = where -o -n "$Cmd" ] && MinArgs=1 || MinArgs=2
  256. if [ $# -lt MinArgs ]; then
  257.     print -ru2 "$Usage
  258. Use -h for help."
  259.     exit
  260. fi
  261.  
  262. if $CmdGiven; then
  263.     # -c given; all args are targets
  264.     # Save targets, since the next set -A will wipe out positional params
  265.     set -A targets -- "$@"    
  266.     # eval this so that quoted options can be given in Cmd
  267.     eval set -A command $Cmd
  268. else
  269.     # First arg is a comma-separated list of targets.
  270.     targets=$1
  271.     shift 1
  272.     if [ $# -eq 0 ]; then
  273.     # eval this so that quoted options can be given in Cmd
  274.     eval set -A command $Cmd
  275.     else
  276.     set -A command "$@"
  277.     fi
  278.     OFS=$IFS
  279.     IFS=,
  280.     set -A targets -- $targets
  281.     IFS=$OFS
  282. fi
  283.  
  284. targList="$*"
  285.  
  286. $Debug && print -ru2 "Command: <${command[*]}>  Targets: <${targets[*]}>"
  287.  
  288. # Command & args now reside in command[]; 
  289. # target executables are in targets[]
  290.  
  291. # If we need to get every instance of a match in the search path (ALL),
  292. # or need to get both executable and non-executable matches (ANYFILE),
  293. # or need to get dangling symlinks (SYMLINKS),
  294. # or need to be able to match shell patterns (SHELLPAT),
  295. # then we must do our own search.  Otherwise we can just use 'whence'.
  296. if [ -n "$ALL" -o -n "$ANYFILE" -o -n "$SYMLINKS" -o -n "$SHELLPAT" ]; then
  297.     OIFS=$IFS
  298.     IFS=:        # Make PATH be split on :
  299.     set -A Paths -- $PATH
  300.     IFS=$OIFS
  301.     LongSearch=true
  302. else
  303.     LongSearch=false
  304. fi
  305.  
  306. # Get full paths to matches.
  307. oPATH=$PATH
  308. PATH=$searchPath
  309. typeset -i numMatch=0
  310. for target in "${targets[@]}"; do
  311.     if $LongSearch; then
  312.     PathSearch "$target"
  313.     else
  314.     set -A Files -- "$(whence -p $target)"    # quick search
  315.     [ -z "$Files" ] && unset Files
  316.     type_i=${#Files[*]}
  317.     fi
  318.     if [ type_i -eq 0 ]; then
  319.     print -ru2 -- "$target: not found"
  320.     else
  321.     $listTargets ||
  322.     set -A TargetExecutables -- "${TargetExecutables[@]}" "${Files[@]}"
  323.     fi
  324.     let numMatch+=type_i
  325. done
  326.  
  327. PATH=$oPATH
  328. # Quit if there were no good targets
  329. [ numMatch -eq 0 ] && exit 1
  330.  
  331. $Debug && print -ru2 "Number of matches: $numMatch"
  332.  
  333. $listTargets && exit 0
  334.  
  335. #if $listTargets; then
  336. #    IFS="
  337. #"
  338. #    print -r -- "${TargetExecutables[*]}"
  339. #    exit 0
  340. #fi
  341.  
  342. # Replace any {} with the list of target executables
  343. typeset -i CmdInd=0 DestInd=0
  344. NoAppend=false
  345. while [ CmdInd -lt ${#command[*]} ]; do
  346.     if [ "${command[CmdInd]}" = {} ]; then
  347.     # Stick target args at end of cmd line being built
  348.     set -A FullCmd -- "${FullCmd[@]}" "${TargetExecutables[@]}"
  349.     DestInd=${#FullCmd[*]}    # Recalculate dest index
  350.     NoAppend=true
  351.     else
  352.     FullCmd[DestInd]=${command[CmdInd]}
  353.     let DestInd+=1
  354.     fi
  355.     let CmdInd+=1
  356. done
  357.  
  358. $NoAppend && unset TargetExecutables[*]
  359.  
  360. if $Test; then
  361.     print -ru2 "Would execute: ${FullCmd[@]} ${TargetExecutables[@]}"
  362.     exit 0
  363. fi
  364.  
  365. a0=${FullCmd[0]} 
  366. [[ -z "$WINTITLE" || -z "$DISPLAY" || -n "$NOTITLE" || \
  367. ${a0##*/} != "${EDITOR##*/}" ]] && NOTITLE=true || NOTITLE=false
  368.  
  369. [ -n "$VERBOSE" ] && 
  370. print -ru2 "Executing: ${FullCmd[@]} ${TargetExecutables[@]}"
  371. $Debug && { print -ru2 "Press return to continue..."; read; }
  372.  
  373. function ResetTitle {
  374.     print -n "\033]0;$OWINTITLE\007"
  375. }
  376.  
  377. if $NOTITLE; then
  378.     exec "${FullCmd[@]}" "${TargetExecutables[@]}"
  379. else
  380.     OWINTITLE=$WINTITLE
  381.     # Change WINTITLE in environment, so that in case another app that
  382.     # uses WINTITLE is run from the editor, it will use modified value
  383.     WINTITLE="$targList ($OWINTITLE)"
  384.     trap ResetTitle INT QUIT
  385.     print -n "\033]0;$WINTITLE\007"      # set win title
  386.     "${FullCmd[@]}" "${TargetExecutables[@]}"
  387.     ResetTitle
  388. fi
  389.