montnaro@sprite.crd.ge.com (Skip Montanaro) (10/03/89)
Does somebody have an elegant shell script for reversing the lines of a file? I've come up with the following short one: ----------cut----------cut----------cut----------cut---------- #!/bin/sh read line if [ $? = 0 ] ; then $0 echo $line fi ----------cut----------cut----------cut----------cut---------- It has two obvious disadvantages. First, it won't work for very long files, since it uses Unix processes to simulate a stack of lines. Second, the Bourne shell's builtin read command doesn't preserve interword white space, separating words by the value of the IFS environment variable instead. It worked adequately for the task I originally intended, however - reversing the lines in my appointements file. -- Skip Montanaro (montanaro@crdgw1.ge.com)
seth@ctr.columbia.edu (Seth Robertson) (10/03/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com> <montanaro@crdgw1.ge.com> (Skip Montanaro) writes: >Does somebody have an elegant shell script for reversing the lines of a >file? I've come up with the following short one: <Recursive code deleted> Ready? *************** *************** ** ** ** tail -r ** ** ** *************** *************** Anything else you want? -- -Seth Robertson seth@ctr.columbia.edu
ok@cs.mu.oz.au (Richard O'Keefe) (10/03/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com>, montnaro@sprite.crd.ge.com (Skip Montanaro) writes: >Does somebody have an elegant shell script for reversing the lines of a file? In BSD systems, cat -n File puts six-digit line numbers and a tab in front of every line. In System V, pr -t -n6 File will do this. Now sort the lines in descending order of line number | sort -nr Now you want to throw away the line numbers. In System V, | cut -f2- will do the job. If you haven't got cut(1), | sed -e 's/^.......//' will strip off the spaces, digits, and tab. So In BSD systems: cat -n $* | sort -nr | sed -e 's/^.......//' In System V: pr -t -n6 $* | sort -nr | cut -f2-
lang@PRC.Unisys.COM (Francois-Michel Lang) (10/03/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com> <montanaro@crdgw1.ge.com> (Skip Montanaro) writes: >Does somebody have an elegant shell script for reversing the lines of a >file? I've come up with the following short one: No need to write a script. tail -r does this already. ---------------------------------------------------------------------------- Francois-Michel Lang Paoli Research Center, Unisys lang@prc.unisys.com (215) 648-7256 Dept of Comp & Info Science, U of PA lang@linc.cis.upenn.edu (215) 898-9511 ---------------------------------------------------------------------------- Francois-Michel Lang Paoli Research Center, Unisys lang@prc.unisys.com (215) 648-7256 Dept of Comp & Info Science, U of PA lang@linc.cis.upenn.edu (215) 898-9511
bin@primate.wisc.edu (Brain in Neutral) (10/03/89)
From article <11628@burdvax.PRC.Unisys.COM>, by lang@PRC.Unisys.COM (Francois-Michel Lang): > No need to write a script. > tail -r does this already. If your tail has -r, that is. Not all do.
cpcahil@virtech.UUCP (Conor P. Cahill) (10/04/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com>, montnaro@sprite.crd.ge.com (Skip Montanaro) writes: > Does somebody have an elegant shell script for reversing the lines of a > file? I've come up with the following short one: How about the following pipeline: grep -n "\$" t.c | sort -rn | sed "s/^[0-9]*://" what this does is as follows: grep - get all lines of the file and number them sort - key is numeric and sort in reverse order sed - remove line numbers added by grep Good luck. -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+
cpcahil@virtech.UUCP (Conor P. Cahill) (10/04/89)
In response to an article about reversing a file... In article <1989Oct3.041122.28028@ctr.columbia.edu>, seth@ctr.columbia.edu (Seth Robertson) writes: > *************** > *************** > ** ** > ** tail -r ** > ** ** > *************** > *************** This wont work on system V (since -r is not an option to tail) and probably wont work on most other unixes if the file is large since tail will only read the last block (not sure of exact size) of the file. This is the problem when you want to get the last 1000 lines in a file of 80 character lines. I haven't found a standard tail that will properly handle this, but I have written one. -- +-----------------------------------------------------------------------+ | Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 ! | Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 | +-----------------------------------------------------------------------+
itkin@mrspoc.Transact.COM (Steven M. List) (10/04/89)
montnaro@sprite.crd.ge.com (Skip Montanaro) writes: >Does somebody have an elegant shell script for reversing the lines of a >file? I've come up with the following short one: This uses one of my all-time favorite VI/EX commands, and this is the first time I can remember anyone ASKING for it: echo "g/./.m0\nw $OUTPUT\nq" | ex $INPUT the "g/./.m0" marks every line in the file and then moves each marked line to the beginning of the file (after line zero). The "w $OUTPUT" will either write the reversed file to a new file or overwrite the original file, depending on whether or not OUTPUT is valued. For those of us who DON'T have "tail -r", this works great! From within VI, you can use the same global command: :g/./.m0 -- +----------------------------------------------------------------------------+ : Steven List @ Transact Software, Inc. :^>~ : : Chairman, Unify User Group of Northern California : : {apple,coherent,limbo,mips,pyramid,ubvax}!itkin@guinan.Transact.COM :
dts@quad.uucp (David T. Sandberg) (10/04/89)
In article <1989Oct3.041122.28028@ctr.columbia.edu> seth@ctr.columbia.edu (Seth Robertson) writes: :In article <MONTNARO.89Oct2224215@sprite.crd.ge.com> <montanaro@crdgw1.ge.com> (Skip Montanaro) writes: :>Does somebody have an elegant shell script for reversing the lines of a :>file? : : tail -r On what system? Tail doesn't have an -r switch on any of the Sys V machines I have access to. Besides, based on the default behavior of tail, this would only affect the last ten lines. (of course, the mythical "-r" flag could alter that behavior, I guess) >Anything else you want? How about something everyone can make use of? -- David Sandberg - Quadric Systems "I began neglecting my shoes." PSEUDO: dts@quad.uucp ACTUAL: ..uunet!rosevax!sialis!quad!dts
dlp@gistdev.UUCP (Dirk Pellett) (10/04/89)
>montnaro@sprite.crd.ge.com (Skip Montanaro) writes: >>Does somebody have an elegant shell script for reversing the lines of a >>file? I've come up with the following short one: itkin@mrspoc.Transact.COM (Steven M. List) replies: >This uses one of my all-time favorite VI/EX commands, and this is the >first time I can remember anyone ASKING for it: > echo "g/./.m0\nw $OUTPUT\nq" | ex $INPUT >the "g/./.m0" marks every line in the file and then moves each marked >line to the beginning of the file (after line zero). Actually, it marks all lines except blank lines. What you really want is the following: echo 'g/^/m0 w q' | ed $1 That way you won't end up will a ton of blank lines at the end of your file. -- -- Dirk Pellett uunet!gistdev!dlp
davr@hrtix.UUCP (David C. Raines) (10/04/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com>, montnaro@sprite.crd.ge.com (Skip Montanaro) writes: > Does somebody have an elegant shell script for reversing the lines of a > file? I've come up with the following short one: Awk version: { array[NR] = $0 } END { for (i = NR; i > 0; i--) print array[i] } -- David Raines TCA 5 National Dr., Windsor Locks, CT 06096 UUCP: ...!uunet!hrtix!davr
jak@sactoh0.UUCP (Jay A. Konigsberg) (10/05/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com> <montanaro@crdgw1.ge.com> (Skip Montanaro) writes: >>Does somebody have an elegant shell script for reversing the lines of a >>file? I've come up with the following short one: ><Recursive code deleted> >Ready? > ** tail -r ** >Anything else you want? This is a nice, clean way to do it, though " tail " had (has?) a bug (feature?) relating to file size. It can't (won't) create a file larger than 512 blocks. Depending on the size of the original file, it could create a problem. -- ############################################################# # Jay Konigsberg # (916) 484-6029 # # SAC-UNIX, Sacramento, Ca. # UUCP=...pacbell!sactoh0!jak # #############################################################
merlyn@iwarp.intel.com (Randal Schwartz) (10/05/89)
In article <2283@munnari.oz.au>, ok@cs (Richard O'Keefe) writes: | In article <MONTNARO.89Oct2224215@sprite.crd.ge.com>, montnaro@sprite.crd.ge.com (Skip Montanaro) writes: | >Does somebody have an elegant shell script for reversing the lines of a file? | In BSD systems: | cat -n $* | sort -nr | sed -e 's/^.......//' | In System V: | pr -t -n6 $* | sort -nr | cut -f2- In Perl, of course, it's perl -e 'unshift(a,$_) while (<STDIN>); print @a;' which works even when 'tail -r' (another solution in another post) doesn't, provided you have the real/virtual memory to spare. Just another Perl hacker, -- /== Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ====\ | on contract to Intel's iWarp project, Hillsboro, Oregon, USA, Sol III | | merlyn@iwarp.intel.com ...!uunet!iwarp.intel.com!merlyn | \== Cute Quote: "Welcome to Oregon... Home of the California Raisins!" ==/
tanner@cdis-1.uucp (Dr. T. Andrews) (10/05/89)
itkin@mrspoc.Transact.COM (Steven M. List) writes:
) echo "g/./.m0\nw $OUTPUT\nq" | ex $INPUT
) :g/./.m0
Very clever, but does not deal effectively with zero-lentgh lines.
In "vi", try the following (similar change for echo command above)
:g/^/.m0
--
He cuts half of passenger service | {bpa,uunet}!cdin-1!cdis-1!tanner
Mulroney: "cold froze our brains" | {attctc gatech!uflorida}!ki4pv!cdis-1!tanner
henseler@uniol.UUCP (Herwig Henseler) (10/06/89)
montnaro@sprite.crd.ge.com (Skip Montanaro) writes: > Does somebody have an elegant shell script for reversing the lines of a > file? The solution in perl: @file = <>; $i = $#file + 1; print $file[$i] while $i--; bye, Herwig -- ## Herwig Henseler (CS-Student) D-2930 Varel, Tweehoernweg 69 | Brain fault- ## ## EMail: henseler@uniol.UUCP (..!uunet!unido!uniol!henseler) | core dumped ##
merlyn@iwarp.intel.com (Randal Schwartz) (10/06/89)
In article <1989Oct3.201759.19182@mrspoc.Transact.COM>, itkin@mrspoc (Steven M. List) writes: | montnaro@sprite.crd.ge.com (Skip Montanaro) writes: | | >Does somebody have an elegant shell script for reversing the lines of a | >file? I've come up with the following short one: | | This uses one of my all-time favorite VI/EX commands, and this is the | first time I can remember anyone ASKING for it: | | echo "g/./.m0\nw $OUTPUT\nq" | ex $INPUT | | the "g/./.m0" marks every line in the file and then moves each marked | line to the beginning of the file (after line zero). The "w $OUTPUT" | will either write the reversed file to a new file or overwrite the | original file, depending on whether or not OUTPUT is valued. | | For those of us who DON'T have "tail -r", this works great! From within | VI, you can use the same global command: | | :g/./.m0 | Arrgh. Both of those fail on *blank* lines. (They'll all end up at either the beginning or the end... I'm too tired to figure out which.) Try: echo "g/^/m0|w $OUTPUT|q" | ex $INPUT instead. Just another 'ex' hacker, -- /== Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ====\ | on contract to Intel's iWarp project, Hillsboro, Oregon, USA, Sol III | | merlyn@iwarp.intel.com ...!uunet!iwarp.intel.com!merlyn | \== Cute Quote: "Welcome to Oregon... Home of the California Raisins!" ==/
bush%ecs.oxford.ac.uk@nsfnet-relay.ac.uk (Mark Bush) (10/07/89)
> Does somebody have an elegant shell script for reversing the lines of a > file? I've come up with the following short one: For all perl fans: while (<>) { $line{$.} = $_; } for ($i = $.; $i > 0; $i--) { print $line{$i}; } Mark Bush bush%uk.ac.oxford.prg@ac.uk Teaching Support Programmer bush%prg.oxford.ac.uk@nsfnet-relay.ac.uk OUCL ...!uunet!mcvax!ukc!ox-prg!bush
jon@jonlab.UUCP (Jon LaBadie) (10/08/89)
A posting asked about how to reverse the sequence of the lines of a file. Generally, my news feed is delayed by 3 - 5 days so I do not post responses to the net, but mail to the poster directly. I assume the answer will be provided by someone else before my posting would ever make it to the net. However, in this case, no one seems to have posted the (IMHO) elegant solution I would propose. Thus, my suggestion for: HOW DO YOU REVERSE THE LINES OF A FILE? ed - ${1} <<! g/^/m0 w q ! Any questions? -- Jon LaBadie {att, princeton, bcr}!jonlab!jon {att, attmail, bcr}!auxnj!jon
ok@cs.mu.oz.au (Richard O'Keefe) (10/08/89)
In article <810@jonlab.UUCP>, jon@jonlab.UUCP (Jon LaBadie) writes: > However, in this case, no one seems to have posted the (IMHO) elegant > solution I would propose. Thus, my suggestion for: > HOW DO YOU REVERSE THE LINES OF A FILE? > ed - ${1} <<! > g/^/m0 > w > q > ! > Any questions? No questions, but several comments. (a) This method, like most others that have been posted, assumes that your virtual memory is at least as big as your file. That's not really an elegant assumption. (I occasionally handled 1/2M files on a PDP-11 with a massive 64k of virtual memory -- no separate I/D.) It's a particularly bad assumption when you bring ed(1) into it, because ed tends to live in the past (be compiled with limits appropriate to a PDP-11 rather than an 80386). For example: ed may strip off the 8th bit of characters ed may truncate lines to 512 characters ed may limit its "work file" to 64k or 128k characters ed may not handle long file names (64 character limit sometimes) ed may just plain not work All of these have hit me in real UNIX releases as provided by vendors. (Not all at the same time.) (b) This method requires the text to already be in a file; it can't be used with a pipe. (A temporary file can be used, but do remember to try $TMPDIR rather than assuming /tmp and do remember to rm it.) (c) The reversed lines are written back onto the original file. That's not necessarily a good idea. The file might be write protected. The intended user might not want that. [d: strange things will happen if any input lines contain NULs, but that also applies to my solution using sort(1), and to any UNIX utility that reads its input with fgets().] In general, The UNIX Way of doing something like this is to make it look as much like a filter as possible.
don@dgbt.uucp (Donald McLachlan) (10/09/89)
If you wnat to reverse the lines from right to left, try the command 'rev filename'.
yahoo@unix.cis.pitt.edu (Kenneth L Moore) (10/13/89)
In article <1260@dgbt.uucp> don@dgbt.uucp (Donald McLachlan) writes: > If you wnat to reverse the lines from right to left, try the >command 'rev filename'. That's a new one. Thanks. Ken -- ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken kne ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken ken
jpr@dasys1.UUCP (Jean-Pierre Radley) (10/13/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com> <montanaro@crdgw1.ge.com> (Skip Montanaro) writes: >Does somebody have an elegant shell script for reversing the lines of a >file? I've come up with the following short one: I don't think I made this up. Maybe I got it from Kernighan & Pike. But it does seem simpler than the answers I've seen posted to date, if you don't have 'tail -r', and if the file isn't too big (whatever that may be, but at some point awk runs out of space). <file awk ' { line[i++] = $0 } END { while (i--) print line[i] } ' -- Jean-Pierre Radley jpr@jpradley.uucp New York, NY 72160.1341@compuserve.com
jc@minya.UUCP (John Chambers) (10/14/89)
In article <MONTNARO.89Oct2224215@sprite.crd.ge.com>, montnaro@sprite.crd.ge.com (Skip Montanaro) writes: > Does somebody have an elegant shell script for reversing the lines of a > file? I've come up with the following short one: ... recursive example deleted ... > It has two obvious disadvantages. First, it won't work for very long files, > since it uses Unix processes to simulate a stack of lines. Second, the > Bourne shell's builtin read command doesn't preserve interword white space, > separating words by the value of the IFS environment variable instead. Here's the fastest way I can think of without stooping to writing in C: for f do ed - $f <<'EOF' g/^/m0 w q EOF done This takes a list of filenames, and reverses each of them. This might not be, strictly speaking, an answer to your question, since it uses ed to do the work, and so it isn't really done by the script. It also has a minor bug (unwanted output) in the boundary case of a null file. But it works for files as large as ed can handle. It's curious that when I used "1,$" instead of "g/^/", it didn't work. I wonder if this is a general ed failing, or if it's just here. -- #echo 'Opinions Copyright 1989 by John Chambers; for licensing information contact:' echo ' John Chambers <{adelie,ima,mit-eddie}!minya!{jc,root}> (617/484-6393)' echo '' saying
jc@minya.UUCP (John Chambers) (10/14/89)
In article <1989Oct3.201759.19182@mrspoc.Transact.COM>, itkin@mrspoc.Transact.COM (Steven M. List) writes: > montnaro@sprite.crd.ge.com (Skip Montanaro) writes: > >Does somebody have an elegant shell script for reversing the lines of a > >file? I've come up with the following short one: > > This uses one of my all-time favorite VI/EX commands, and this is the > first time I can remember anyone ASKING for it: > echo "g/./.m0\nw $OUTPUT\nq" | ex $INPUT > the "g/./.m0" marks every line in the file and then moves each marked > line to the beginning of the file (after line zero). No, it doesn't. You didn't test it against a file containing null lines. If you had, you would have discovered that the "g/./" only matches lines with characters in them. So what you get is the non-null lines in reverse order, followed by as many null lines as were in the original file. Try: echo "g/^/m0\nw $OUTPUT\nq" | ex $INPUT Note also that the second dot, while not wrong, is not needed. (I guess you flunk your ex-wizard test. Now if I could only figure out how to type map commands to vi so that it does something useful, rather than giving me error messages. ;-) > The "w $OUTPUT" > will either write the reversed file to a new file or overwrite the > original file, depending on whether or not OUTPUT is valued. That's clever. -- #echo 'Opinions Copyright 1989 by John Chambers; for licensing information contact:' echo ' John Chambers <{adelie,ima,mit-eddie}!minya!{jc,root}> (617/484-6393)' echo '' saying
tony@oha.UUCP (Tony Olekshy) (10/14/89)
Hmm, in the interest of further promoting perl: @L = <stdin>; print pop(@L) while $#L+1; # Read FIFO, Write LIFO! -- Yours, etc., Tony Olekshy (...!alberta!oha!tony or tony@oha.UUCP).
chris@mimsy.UUCP (Chris Torek) (10/14/89)
In article <39@minya.UUCP> jc@minya.UUCP (John Chambers) writes: >... g/^/m0 ... >It's curious that when I used "1,$" instead of "g/^/", it didn't work. >I wonder if this is a general ed failing, or if it's just here. It is a feature. `g/pat/cmd' applies `cmd' to each line matching `pat'---meaning each line is examined one at a time, and if it matches, `cmd' is done. `1,$cmd', however, applies `cmd' to the range 1,$. It should become obvious what is going on: The first command moves line 1 after line 0, then (what was, and here still is) line 2 after line 0, and then moves line 3 after 0, and so forth. The second moves all the lines, as a single unit, to after line 0. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris