home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / unix / shell / 3905 < prev    next >
Encoding:
Internet Message Format  |  1992-09-11  |  4.6 KB

  1. Path: sparky!uunet!charon.amdahl.com!amdahl!krs
  2. From: krs@uts.amdahl.com (Kris Stephens [Hail Eris!])
  3. Newsgroups: comp.unix.shell
  4. Subject: Re: Substring of a file name
  5. Summary: long followup because of performance considerations in the scripting
  6. Message-ID: <02tT03R280oV00@amdahl.uts.amdahl.com>
  7. Date: 11 Sep 92 16:39:21 GMT
  8. References: <37016@uflorida.cis.ufl.edu> <JDELL.92Sep10180225@golda.mit.edu>
  9. Distribution: usa
  10. Organization: Amdahl Corporation, Sunnyvale CA
  11. Lines: 139
  12.  
  13. On 10 Sep 92 15:15:41 GMT, urs@carp.cis.ufl.edu (Uppili Srinivasan) said:
  14. >Nntp-Posting-Host: carp.cis.ufl.edu
  15. >Hi,
  16. >I need to write a script to read a substring of some of the filenames
  17. >in a directory. (i.e) if xy1992 is the name i need to read the last four
  18. >letters only. I guess 'awk' is ideal for this . But I am curious to
  19. >know the other ways of doing this.
  20.  
  21. Actually, awk isn't that great a choice here.  Yeah, it's got substring
  22. matching and editing capability, but it's better at whole-token work.
  23.  
  24. A sed example was posted, and it'll work to strip the first two alpha
  25. characters off.  What concerns me is that it'd wind up invoking sed
  26. once for each file in the directory.  A better approach is to locate
  27. the directory and shove all the files through one call to sed.
  28.  
  29. Beware of one thing: different versions of sh and ksh (levels and OSes)
  30. will decide differently when to fork subshells in the while loop.
  31.  
  32. See after the script for some other mods I'd make if needed.
  33.  
  34. ---- example.sh ----
  35. :
  36. # This is sh or ksh to grab the last four characters of all the filenames
  37. # in the $1 directory and, if they're numeric, associate them with the
  38. # filenames.  The likely point is that the directory contains files which
  39. # are yearly summaries or some such.
  40. #
  41. if [ $# -ne 1 ]
  42. then
  43.     echo "usage: $0 directory" 1>&2
  44.     exit 1
  45. fi
  46. if [ ! -d $1 ]
  47. then
  48.     echo "$0: '$1' - not a directory" 1>&2
  49.     exit 1
  50. fi
  51.  
  52. #
  53. # Okay, we've got a directory
  54. #
  55. cd $1
  56.  
  57. #
  58. # List the files and use sed to    replicate the last four characters as
  59. # a second word if those characters are numeric.
  60. #
  61. ls |
  62.  
  63. sed 's/[0-9]\{4\}$/& &/' |
  64.  
  65. #
  66. # Read in filename and year if available, skipping files that didn't
  67. # have a year associated.
  68. #
  69. while read file year
  70. do
  71.     [ -z "$year" ] && continue    # no year at the end; check next file
  72.  
  73.     :                # do what needs to be done
  74. done
  75. ---- end example.sh ----
  76.  
  77. IFF (if and *only* if!) this script will only be needed for files dated
  78. 1900-1999, I'd be tempted to rewrite the sed like
  79.  
  80.     sed 's/19[0-9][0-9]$/& &/' |
  81.  
  82. because it may be easier to read.
  83.  
  84. ------
  85. From this point on, the while loop won't need to test to see if $year is
  86. null -- the modifications do the job in the pipeline.
  87.  
  88. If the directory has (or may have) a *lot* of files in it that don't end
  89. in years (i.e. chaffe to be deleted), I alter the sed:
  90.  
  91.     #
  92.     # sed to
  93.     #    delete all filenames which don't end in 4 numbers, then
  94.     #    replicate the last four characters (numbers) as word 2
  95.     #
  96.     sed    -e '/[0-9]\{4\}$/!d'    \
  97.         -e 's/.\{4\}$/& &/'    |
  98.  
  99. to have it strip the non-matching files so we never get them in the loop.
  100.  
  101. And if there are a bazillion files to handle, some matching some not, I'd
  102. take the filter job away from sed and toss a grep into the pipeline:
  103.  
  104.     # get the filenames
  105.     ls |
  106.  
  107.     # get rid of files not ending in four numbers
  108.     grep '[0-9]\{4\}$' |
  109.  
  110.     # duplicate the last four chars (numbers) as a second word
  111.     sed 's/.\{4\}$/& &/' |
  112.  
  113. This is because making three small calls (ls, grep, sed), each doing a very
  114. little of exactly what they're designed to do, is faster than one program
  115. trying to do a lot against a lot of data.  The stream will definitely outrun
  116. the while read loop.  There are more ways to speed it up if needed, but
  117. usually this is sufficient for even pretty heavy-duty lists.  Testing for
  118. subdirectories while correctly handling symbolic links is another tricky
  119. part, but this article is already too long.
  120.  
  121. One other thing, though.  I used ls with no filename args because if we did
  122.  
  123.     ls -d *[0-9][0-9][0-9][0-9] |
  124.  
  125. we'd actually be processing all the filenames twice in that one line: once
  126. by the shell (to build the argument list) and once by ls (to list them).
  127. Here's the last possible tweak:
  128.  
  129.     #
  130.     # list the files that end with four numbers
  131.     #
  132.     echo *[0-9][0-9][0-9][0-9] |
  133.  
  134.     #
  135.     # turn spaces into line-ends
  136.     #
  137.     tr ' ' '\012' |
  138.  
  139.     #
  140.     # duplicate the last four chars (numbers) as a second word
  141.     #
  142.     sed 's/.\{4\}$/& &/' |
  143.  
  144. I don't know of a faster approach at shell level.
  145.  
  146. ...Kris
  147. -- 
  148. Kristopher Stephens, | (408-746-6047) | krs@uts.amdahl.com | KC6DFS
  149. Amdahl Corporation   |                |                    |
  150.      [The opinions expressed above are mine, solely, and do not    ]
  151.      [necessarily reflect the opinions or policies of Amdahl Corp. ]
  152.