views:

919

answers:

4

How can I randomize the lines in a file using a standard tools on Redhat Linux?

I don't have the "shuf" command, so I am looking for something like a perl or awk one liner that accomplishes the same task.

+2  A: 

And a Perl one-liner you get!

perl -MList::Util -e 'print List::Util::shuffle <>'

It uses a module, but the module is part of the Perl code distribution. If that's not good enough, you may consider rolling your own.

I tried using this with the -i flag ("edit-in-place") to have it edit the file. The documentation suggests it should work, but it doesn't. It still displays the shuffled file to stdout, but this time it deletes the original. I suggest you don't use it.

Consider a shell script:

#!/bin/sh

if [[ $# -eq 0 ]]
then
  echo "Usage: $0 [file ...]"
  exit 1
fi

for i in "$@"
do
  perl -MList::Util -e 'print List::Util::shuffle <>' $i > $i.new
  if [[ `wc -c $i` -eq `wc -c $i.new` ]]
  then
    mv $i.new $i
  else
    echo "Error for file $i!"
  fi
done

Untested, but hopefully works.

Chris Lutz
The perl one-liner worked great! Thanks!
Stuart Woodward
To backup the original file, you can suffix an extension to the -i flag [http://perldoc.perl.org/perlrun.html]
Steve Schnepp
+2  A: 
cat yourfile.txt | while read f ; do printf "$RANDOM\t%s\n" "$f"; done | sort -n | cut -f2-

Read the file, prepend every line with a random number, sort the file on those random prefixes, cut the prefixes afterwards. One-liner which should work in any semi-modern shell.

ChristopheD
This works, and is a creative solution, but will delete leading whitespace on lines.
Chris Lutz
@Chris changing the last cut to |sed 's/^[^\t]*\t//' should fix that
bdonlan
Kudos to the simplicity of the approach!
Shashikant Kore
Nice try, but even changing to the sed command deletes whitespace.
Stuart Woodward
Try this: `cat yourfile.txt | while read f ; do printf "%05d %s\n" "$(( $RANDOM % 100000 ))" "$f"; done | sort -n | cut -c7-`
jwhitlock
+4  A: 

Um, lets not forget

sort --random-sort
Jim T
All these cool features that I don't have on OS X! Dammit!
Chris Lutz
Could you tell me which version of sort has this option?
Stuart Woodward
Well, I'm using gnu-coreutils 7.1 (standard gentoo install), which has sort with this option, not sure when it appeared, or if it's in other implementations.
Jim T
The feature was committed on 10th December 2005, the release following that was 5.94, so I'm guessing it's been available since that version.
Jim T
+1  A: 

Related to Jim's answer:

My ~/.bashrc contains the following:

unsort ()
{
    LC_ALL=C sort -R "$@"
}

With GNU coreutils's sort, -R = --random-sort, which generates a random hash of each line and sorts by it. The randomized hash wouldn't actually be used in some locales in some older (buggy) versions, causing it to return normal sorted output, which is why I set LC_ALL=C.


Related to Chris's answer:

perl -MList::Util=shuffle -e'print shuffle<>'

is a slightly shorter one-liner. (-Mmodule=a,b,c is shorthand for -e 'use module qw(a b c);'.)

The reason giving it a simple -i doesn't work for shuffling in-place is because Perl expects that the print happens in the same loop the file is being read, and print shuffle <> doesn't output until after all input files have been read and closed.

As a shorter workaround,

perl -MList::Util=shuffle -i -ne'BEGIN{undef$/}print shuffle split/^/m'

will shuffle files in-place. (-n means "wrap the code in a while (<>) {...} loop; BEGIN{undef$/} makes Perl operate on files-at-a-time instead of lines-at-a-time, and split/^/m is needed because $_=<> has been implicitly done with an entire file instead of lines.)

ephemient
Reiterating that sort -R doesn't exist on OS X, but +1 for some great Perl answers, and a great answer in general.
Chris Lutz
You could install GNU coreutils on OS X, but (as I've done in the past) you have to be careful not to break the built-in tools... That being said, OP is on Redhat Linux, which definitely has GNU coreutils standard.
ephemient