add each column to array, not just whole line - PERL - arrays

I am writing a perl script and currently working on a subroutine to sum all values of an array. Currently, my code only reads in each line and stores the entire line into each array element. I need each individual number stored in it's own element.
Here's a sample of my data:
50 71 55 93 115
45 76 49 88 102
59 78 53 96 145
33 65 39 82 100
54 77 56 98 158
Here's my code:
my #array;
#bring in each line and store into array called 'array'
open(my $fh, "<", "score")
or die "Failed to open file: $!\n";
while(<$fh>) {
chomp;
push #array, $_;
}
close $fh;
When I call my subroutine to sum the values of the array, my result is 241. That is the sum of each of the first numbers in each line.
Any help or suggestions?

So, you want to add all values inside an array. Easy, But In your code, you are adding strings of values instead of value itself.
With push #array, $_; you are creating an array of lines in the file score.
Try:
print Dumper(\#array);
You will see output like this:
$VAR1 = [
'50 71 55 93 115',
'45 76 49 88 102',
'59 78 53 96 145',
'33 65 39 82 100',
'54 77 56 98 158'
];
So when you are adding the values, it adds all elements of array:
'50 71 55 93 115' + '59 78 53 96 145' + '33 65 39 82 100' ......and so on
The moment you put + with string it is treated as numeric and by default, perl adds first character in the string to the first character in the other string. If the first character is not a number, It is treated as 0.
You should check perlop for more info.
The solution for this problem is to separate the numbers from every line, treat each of them individually and store them inside the array. This can be done simply using:
push #array, split;
Now when you try:
print Dumper(\#array);
It will be like this:
$VAR1 = [
'50',
'71',
'55',
'93',
'115',
'45',
'76',
'49',
'88',
'102',
'59',
'78',
'53',
'96',
'145',
'33',
'65',
'39',
'82',
'100',
'54',
'77',
'56',
'98',
'158'
];
After this just call your subroutine using:
my $total_sum = sum(#array);
print $total_sum,"\n";
and define your subroutine as:
sub sum {
my #nums = #_;
my $total_sum = 0;
$total_sum += $_ foreach(#nums);
return $total_sum;
}
The output will be 1937 as expected.

Related

Why after the while loop I am only getting last row value?

This is the files I am reading,
#Log1
Time Src_id Des_id Address
0 34 56 x9870
2 36 58 x9872
4 38 60 x9874
6 40 62 x9876
8 42 64 x9878
#Log2
Time Src_id Des_id Address
1 35 57 x9871
3 37 59 x9873
5 39 61 x9875
7 41 63 x9877
9 43 65 x9879
This the code I wrote where I am reading line by line and then spliting it
#!usr/bin/perl
use warnings;
use strict;
my $log1_file = "log1.log";
my $log2_file = "log2.log";
open(IN1, "<$log1_file" ) or die "Could not open file $log1_file: $!";
open(IN2, "<$log2_file" ) or die "Could not open file $log2_file: $!";
my $i_d1;
my $i_d2;
my #fields1;
my #fields2;
while (my $line = <IN1>) {
#fields1 = split " ", $line;
}
while (my $line = <IN2>) {
#fields2 = split " ", $line;
}
print "#fields1\n";
print "#fields2\n";
close IN1;
close IN2;
Output I am getting
8 42 64 x9878
9 43 65 x9879
Output Desired
Time Src_id Des_id Address
0 34 56 x9870
2 36 58 x9872
4 38 60 x9874
6 40 62 x9876
8 42 64 x9878
9 43 65 x9879
Time Src_id Des_id Address
1 35 57 x9871
3 37 59 x9873
5 39 61 x9875
7 41 63 x9877
9 43 65 x9879
If I use push(#fields1 , split " ", $line); I am getting output like this,
Time Src_id Des_id Address 0 34 56 x9870 B 36 58 x9872 D 38 60 x9874 F 40 62 x9876 H 42 64 x9878
It should print whole array but printing just last row?
Also after this I need to compare both the "Times" part of both log & print in sequence way but don't know how to run both array simultaneously in while loop?
Please suggest in standard way without any modules because I need to run this in someone else server.
Following code demonstrates how to read and print log files
(OP does not specify why he splits lines into fields)
use strict;
use warnings;
use feature 'say';
my $fname1 = 'log1.txt';
my $fname2 = 'log2.txt';
my $div = "\t";
my $file1 = read_file($fname1);
my $file2 = read_file($fname2);
print_file($file1,$div);
print_file($file2,$div);
sub read_file {
my $fname = shift;
my #data;
open my $fh, '<', $fname
or die "Couldn't read $fname";
while( <$fh> ) {
chomp;
next if /^#Log/;
push #data, [split];
}
close $fh;
return \#data;
}
sub print_file {
my $data = shift;
my $div = shift;
say join($div,#{$_}) for #{$data};
}
Output
Time Src_id Des_id Address
0 34 56 x9870
2 36 58 x9872
4 38 60 x9874
6 40 62 x9876
8 42 64 x9878
Time Src_id Des_id Address
1 35 57 x9871
3 37 59 x9873
5 39 61 x9875
7 41 63 x9877
9 43 65 x9879
Let's assume that OP wants to merge two files into one with sorted lines on Time field
read files into %data hash with Time field as key
print header (#fields)
print hash values sorted on Time key
use strict;
use warnings;
use feature 'say';
my(#fields,%data);
my $fname1 = 'log1.txt';
my $fname2 = 'log2.txt';
read_data($fname1);
read_data($fname2);
say join("\t",#fields);
say join("\t",#{$data{$_}}) for sort { $a <=> $b } keys %data;
sub read_data {
my $fname = shift;
open my $fh, '<', $fname
or die "Couldn't open $fname";
while( <$fh> ) {
next if /^#Log/;
if( /^Time/ ) {
#fields = split;
} else {
my #line = split;
$data{$line[0]} = \#line;
}
}
close $fh;
}
Output
Time Src_id Des_id Address
0 34 56 x9870
1 35 57 x9871
2 36 58 x9872
3 37 59 x9873
4 38 60 x9874
5 39 61 x9875
6 40 62 x9876
7 41 63 x9877
8 42 64 x9878
9 43 65 x9879
Because #fields* gets overwritten during each loop. You need this:
while(my $line = <IN1>){
my #tmp = split(" ", $line);
push(#fields1, \#tmp);
}
foreach $item (#fields1){
print("#{$item}\n");
}
Then #fields1 contains references pointing to the splited array.
The final #fields1 looks like:
#fields1 = (
<ref> ----> ["0", "34", "56", "x9870"]
<ref> ----> ["2", "36", "58", "x9872"]
...
)
The print will print:
Time Src_id Des_id Address
0 34 56 x9870
2 36 58 x9872
4 38 60 x9874
6 40 62 x9876
8 42 64 x9878
And I guess it would be better if you do chomp($line).
But I'd like to simply do push(#fields1, $line). And split each array item when in comparison stage.
To compare the content of 2 files, I personally would use 2 while loops to read into 2 arrays just like what you have done. Then do the comparison in one for or foreach.
You can merge the log files using paste, and read the resulting merged file one line at a time. This is more elegant and saves RAM. Here is an example of a possible comparison of time1 and time2, writing STDOUT and STDERR into separate files. The example prints into STDOUT all the input fields if time1 < time2 and time1 < 4, otherwise prints a warning into STDERR:
cat > log1.log <<EOF
Time Src_id Des_id Address
0 34 56 x9870
2 36 58 x9872
4 38 60 x9874
6 40 62 x9876
8 42 64 x9878
EOF
cat > log2.log <<EOF
Time Src_id Des_id Address
1 35 57 x9871
3 37 59 x9873
5 39 61 x9875
7 41 63 x9877
9 43 65 x9879
EOF
# Paste files side by side, skip header, read data lines together, compare and print:
paste log1.log log2.log | \
tail -n +2 | \
perl -lane '
BEGIN {
for $file_num (1, 2) { push #col_names, map { "$_$file_num" } qw( time src_id des_id address ) }
}
my %val;
#val{ #col_names } = #F;
if ( $val{time1} < $val{time2} and $val{time1} < 4) {
print join "\t", #val{ #col_names};
} else {
warn "not found: #val{ qw( time1 time2 ) }";
}
' 1>out.tsv 2>out.log
Output:
% cat out.tsv
0 34 56 x9870 1 35 57 x9871
2 36 58 x9872 3 37 59 x9873
% cat out.log
not found: 4 5 at -e line 10, <> line 3.
not found: 6 7 at -e line 10, <> line 4.
not found: 8 9 at -e line 10, <> line 5.
The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.
-a : Split $_ into array #F on whitespace or on the regex specified in -F option.
SEE ALSO:
perldoc perlrun: how to execute the Perl interpreter: command line switches

creating an array of arrays in perl and deleting from the array

I'm writing this to avoid a O(n!) time complexity but I only have pseudocode right now because there are some things I'm unsure about implementing.
This is the format of the file that I want to pass into this script. The data is sorted by the third column -- the start position.
93 Blue19 1 82
87 Green9 1 7912
76 Blue7 2 20690
65 Red4 2 170
...
...
256 Orange50 17515 66740
166 Teal68 72503 123150
228 Green89 72510 114530
Explanation of the code:
I want to create an array of arrays to find when two pieces of information have overlapping lengths.
Columns 3 and 4 of the input file are start and stop positions on a single track line. If any row(x) has a position in column 3 that is shorter than the position in column 4 in any row(y) then this means that x starts before y ends and there is some overlap.
I want to find every row that overlaps with asnyrow without having to compare every row to every row. Because they are sorted I simply add a string to an inner array of the array which represents one row.
If the new row being looked at does not overlap with one of the rows already in the array then (because the array is sorted by the third column) no further row will be able to overlap with the row in the array and it can be removed.
This is what I have an idea of
#!/usr/bin/perl -w
use strict;
my #array
while (<>) {
my thisLoop = ($id, $name, $begin, $end) = split;
my #innerArray = split; # make an inner array with the current line, to
# have strings that will be printed after it
push #array(#innerArray)
for ( #array ) { # loop through the outer array being made to see if there
# are overlaps with the current item
if ( $begin > $innerArray[3]) # if there are no overlaps then print
# this inner array and remove it
# (because it is sorted and everything
# else cannot overlap because it is
# larger)
# print #array[4-]
# remove this item from the array
else
# add to array this string
"$id overlap with innerArray[0] \t innerArray[0]: $innerArray[2], $innerArray[3] "\t" $id : $begin, $end
# otherwise because there is overlap add a statement to the inner
# array explaining the overlap
The code should produce something like
87 overlap with 93 93: 1 82 87: 1 7982
76 overlap with 93 93: 1 82 76: 1 20690
65 overlap with 93 93: 1 82 65: 2 170
76 overlap with 87 87: 1 7912 76: 2 20690
65 overlap with 87 87: 1 7912 65: 2 170
65 overlap with 76 76: 2 20690 65: 2 170
256 overlap with 76 76: 2 20690 256: 17515 66740
228 overlap with 166 166: 72503 123150 228: 72510 114530
This was tricky to explain so ask me if you have any questions
I am using the posted input and output files as a guide on what is required.
A note on complexity. In principle, each line has to be compared to all following lines. The number of operations actually carried out depends on the data. Since it is stated that the data is sorted on the field to be compared the inner loop iterations can be cut as soon as overlapping stops. A comment on complexity estimate is at the end.
This compares each line to the ones following it. For that all lines are first read into an array. If the data set is very large this should be changed to read line by line and then the procedure turned around, to compare the currently read line to all previous. This is a very basic approach. It may well be better to build auxiliary data structures first, possibly making use of suitable libraries.
use warnings;
use strict;
my $file = 'data_overlap.txt';
my #lines = do {
open my $fh, '<', $file or die "Can't open $file -- $!";
<$fh>;
};
# For each element compare all following ones, but cut out
# as soon as there's no overlap since data is sorted
for my $i (0..$#lines)
{
my #ref_fields = split '\s+', $lines[$i];
for my $j ($i+1..$#lines)
{
my #curr_fields = split '\s+', $lines[$j];
if ( $ref_fields[-1] > $curr_fields[-2] ) {
print "$curr_fields[0] overlap with $ref_fields[0]\t" .
"$ref_fields[0]: $ref_fields[-2] $ref_fields[-1]\t" .
"$curr_fields[0]: $curr_fields[-2] $curr_fields[-1]\n";
}
else { print "\tNo overlap, move on.\n"; last }
}
}
With the input in file 'data_overlap.txt' this prints
87 overlap with 93 93: 1 82 87: 1 7912
76 overlap with 93 93: 1 82 76: 2 20690
65 overlap with 93 93: 1 82 65: 2 170
No overlap, move on.
76 overlap with 87 87: 1 7912 76: 2 20690
65 overlap with 87 87: 1 7912 65: 2 170
No overlap, move on.
65 overlap with 76 76: 2 20690 65: 2 170
256 overlap with 76 76: 2 20690 256: 17515 66740
No overlap, move on.
No overlap, move on.
No overlap, move on.
228 overlap with 166 166: 72503 123150 228: 72510 114530
A comment on complexity
Worst case Each element has to be compared to every other (they all overlap). This means that for each element we need N-1 comparisons, and we have N elements. This is O(N^2) complexity. This complexity is not good for operations that are used often and on potentially large data sets, like what libraries do. But it is not necessarily bad for a particular problem -- the data set still needs to be quite large for that to result in prohibitively long runtimes.
Best case Each element is compared only once (no overlap at all). This implies N comparisons, thus O(N) complexity.
Average Let us assume that each element overlaps with a "few" next ones, let us say 3 (three). This means that there would be 3N comparisons. This is still O(N) complexity. This holds as long as the number of comparisons does not depend on the length of the list (but is constant), which is a very reasonable typical scenario here. This is good.
Thanks to ikegami for bringing this up in the comment, along with the estimate.
Remember that the importance of the computational complexity of a technique depends on its use.
This produces exactly the output that you asked for given your sample data as input. It runs in well under one millisecond
Do you have other constraints that you haven't explained? Making your code run faster should never be an end in itself. There is nothing inherently wrong with an O(n!) time complexity: it is the execution time that you must consider, and if your code is fast enough then your job is done
use strict;
use warnings 'all';
my #data = map [ split ], grep /\S/, <DATA>;
for my $i1 ( 0 .. $#data ) {
my $v1 = $data[$i1];
for my $i2 ( $i1 .. $#data ) {
my $v2 = $data[$i2];
next if $v1 == $v2;
unless ( $v1->[3] < $v2->[2] or $v1->[2] > $v2->[3] ) {
my $statement = sprintf "%d overlap with %d", $v2->[0], $v1->[0];
printf "%-22s %d: %d %-7d %d: %d %-7d\n", $statement, #{$v1}[0, 2, 3], #{$v2}[0, 2, 3];
}
}
}
__DATA__
93 Blue19 1 82
87 Green9 1 7912
76 Blue7 2 20690
65 Red4 2 170
256 Orange50 17515 66740
166 Teal68 72503 123150
228 Green89 72510 114530
output
87 overlap with 93 93: 1 82 87: 1 7912
76 overlap with 93 93: 1 82 76: 2 20690
65 overlap with 93 93: 1 82 65: 2 170
76 overlap with 87 87: 1 7912 76: 2 20690
65 overlap with 87 87: 1 7912 65: 2 170
65 overlap with 76 76: 2 20690 65: 2 170
256 overlap with 76 76: 2 20690 256: 17515 66740
228 overlap with 166 166: 72503 123150 228: 72510 114530

Array manipulation in Perl

The Scenario is as follows:
I have a dynamically changing text file which I'm passing to a variable to capture a pattern that occurs throughout the file. It looks something like this:
my #array1;
my $file = `cat <file_name>.txt`;
if (#array1 = ( $file =~ m/<pattern_match>/g) ) {
print "#array1\n";
}
The array looks something like this:
10:38:49 788 56 51 56 61 56 59 56 51 56 80 56 83 56 50 45 42 45 50 45 50 45 43 45 54 10:38:51 788 56 51 56 61 56 59 56 51 56 80 56 83 56 50 45 42 45 50 45 50 45 43 45 54
From the above array1 output, the pattern of the array is something like this:
T1 P1 t1(1) t1(2)...t1(25) T2 P2 t2(1) t2(2)...t2(25) so on and so forth
Currently, /g in the regex returns a set of values that occur only twice (only because the txt file contains this pattern that number of times). This particular pattern occurrence will change depending on the file name that I plan to pass dynamically.
What I intend to acheive:
The final result should be a csv file that contains these values in the following format:
T1,P1,t1(1),t1(2),...,t1(25)
T2,P2,t2(1),t2(2),...,t2(25)
so on and so forth
For instance: My final CSV file should look like this:
10:38:49,788,56,51,56,61,56,59,56,51,56,80,56,83,56,50,45,42,45,50,45,50,45,43,45,54
10:38:51,788,56,51,56,61,56,59,56,51,56,80,56,83,56,50,45,42,45,50,45,50,45,43,45,54
The delimiter for this pattern is T1 which is time in the format \d\d:\d\d:\d\d
Example: 10:38:49, 10:38:51 etc
What I have tried so far:
use Data::Dumper;
use List::MoreUtils qw(part);
my $partitions = 2;
my $i = 0;
print Dumper part {$partitions * $i++ / #array1} #array1;
In this particular case, my $partitions = 2; holds good since the pattern occurrence in the txt file is only twice, and hence, I'm splitting the array into two. However, as mentioned earlier, the pattern occurrence number keeps changing according to the txt file I use.
The Question:
How can I make this code more generic to achieve my final goal of splitting the array into multiple equal sized arrays without losing the contents of the original array, and then converting these mini-arrays into one single CSV file?
If there is any other workaround for this other than array manipulation, please do let me know.
Thanks in advance.
PS: I considered Hash of Hashes and Array of Hashes, but that kind of a data structure did not seem to be healthy solution for the problem I'm facing right now.
As far as I can tell, all you need is splice, which will work fine as long as you know the record size and it's constant
The data you showed has 52 fields, but the description of it requires 27 fields per record. It looks like each line has T, P, and t1 .. t24, rather than ending at t25
Here's how it looks if I split the data into 26-element chunks
use strict;
use warnings 'all';
my #data = qw/
10:38:49 788 56 51 56 61 56 59 56 51 56 80 56 83 56 50 45 42 45 50 45 50 45 43 45 54 10:38:51 788 56 51 56 61 56 59 56 51 56 80 56 83 56 50 45 42 45 50 45 50 45 43 45 54
/;
while ( #data ) {
my #set = splice #data, 0, 26;
print join(',', #set), "\n";
}
output
10:38:49,788,56,51,56,61,56,59,56,51,56,80,56,83,56,50,45,42,45,50,45,50,45,43,45,54
10:38:51,788,56,51,56,61,56,59,56,51,56,80,56,83,56,50,45,42,45,50,45,50,45,43,45,54
If you wanted to use List::MoreUtils instead of splice, the the natatime function returns an iterator that will do the same thing as the splice above
Like this
use List::MoreUtils qw/ natatime /;
my $iter = natatime 26, #data;
while ( my #set = $iter->() ) {
print join(',', #set), "\n";
}
The output is identical to that of the program above
Note
It is very wrong to start a new shell process just to use cat to read a file. The standard method is to undefine the input record separator $/ like this
my $file = do {
open my $fh, '<', '<file_name>.txt' or die "Unable to open file for input: $!";
local $/;
<$fh>;
};
Or if you prefer you could use File::Slurper like this
use File::Slurper qw/ read_binary /;
my $file = read_binary '<file_name>.txt';
although you will probably have to install it as it is not a core module

How could I print a #slice array elements in Perl?

I have this part of code to catch the greater value of an array immersed in a Hash. When Perl identified the biggest value the array is removed by #slice array:
if ( max(map $_->[1], #$val)){
my #slice = (#$val[1]);
my #ignored = #slice;
delete(#$val[1]);
print "$key\t #ignored\n";
warn Dumper \#slice;
}
Data:Dumper out:
$VAR1 = [
[
'3420',
'3446',
'13',
'39',
55
]
];
I want to print those information separated by tabs (\t) in one line like this list:
miRNA127 dvex589433 - 131 154
miRNA154 dvex546562 + 232 259
miRNA154 dvex573491 + 297 324
miRNA154 dvex648254 + 147 172
miRNA154 dvex648254 + 287 272
miRNA32 dvex320240 - 61 83
miRNA32 dvex623745 - 141 163
miRNA79 dvex219016 + ARRAY(0x100840378)
But in the last line always obtain this result.
How could I generate this output?:
miRNA127 dvex589433 - 131 154
miRNA154 dvex546562 + 232 259
miRNA154 dvex573491 + 297 324
miRNA154 dvex648254 + 147 172
miRNA154 dvex648254 + 287 272
miRNA32 dvex320240 - 61 83
miRNA32 dvex623745 - 141 163
miRNA79 dvex219016 + 3420 3446
Additional explication:
In this case, I want to catch the highest value in $VAR->[1] and looking if the subtraction with the minimum in $VAR->[0] is <= to 55. If not, i need to eliminate this AoA (the highest value) and fill a #ignored array with it. Next, i want to print some values of #ignored, like a list. Next, with the resultants AoA, I want to iterate the last flow...
print "$key\t $ignored[0]->[0]\t$ignored[0]->[1]";
You have an array of arrays, so each element of #ignored is an array. The notation $ignored[0] gets to the zeroth element (which is an array), and ->[0] and ->[1] retrieves the zeroth and first elements of that array.
For example:
use strict;
use warnings;
use Data::Dumper;
my #ignored;
$ignored[0] = [ '3420', '3446', '13', '39', 55 ];
my $key = 'miRNA79 dvex219016 +';
print Dumper \#ignored;
print "\n";
print "$key\t$ignored[0]->[0]\t$ignored[0]->[1]";
Output:
$VAR1 = [
[
'3420',
'3446',
'13',
'39',
55
]
];
miRNA79 dvex219016 + 3420 3446
Another option that generates the same output is to join all the values with a \t:
print join "\t", $key, #{ $ignored[0] }[ 0, 1 ];

Bash random number generator where number is not in array

I am attempting to create a random number generator that generates a number between 1 and 99 but not any number that has already been generated.
In the script array1 contains the numbers already generated. To make it easier to test I have reduced the random number range to 0 - 14 and manually created an array.
I am quite new to bash scripting and am picking it up with a couple of books and the internet.
I have tried a mixture of ideas, the one that seems to make most sense is
array1=( 1 2 3 6 7 8 9 10 11 12 13 )
func1() {
for var in "${array1[#]}"
do
echo $var
done
}
rnd=$[ $RANDOM % 14 ]
until [ $rnd != func1 ]
do
rnd=$[ $RANDOM % 14 ]
done
echo $rnd
however I know the problem is on line 9 the shell sees the following code:
until [ $rnd != 1 2 3 6 7 8 9 10 11 12 13 ]
I know that the solution is that line 9 needs to be:
until [ $rnd != 1 ] && [ $rnd != 2 ] && [ $rnd != 3 ] && ...
I just don't know how to make this happen automatically from the array. The array does vary in length depending on how many numbers have been generated.
Any help will be greatly appreciated!
This is something that I found difficulty doing in bash. The approach I came up with is to have func1() return true or false and modify the array to remove the number that has been picked.
array=( {1..15} )
func1() {
local pick="$1"
found=1
total=${#array[#]}
for ((i=0;i<total;i++)); do
if (( pick == ${array[i]} )); then
echo $pick
array=( ${array[#]:0:i} ${array[#]:((i + 1)):$total})
found=0
break
fi
done
return $found
}
numbers=3
for ((x=0;x<numbers;x++)); do
until func1 $(( $RANDOM % ( ${#array[#]} ) )); do
continue
done
done
As noted in one of the comments, using the Knuth Shuffle is an excellent way to do this
#!/bin/bash
shuffle() {
local i tmp size max rand
# Code from http://mywiki.wooledge.org/BashFAQ/026
# $RANDOM % (i+1) is biased because of the limited range of $RANDOM
# Compensate by using a range which is a multiple of the array size.
size=${#array[*]}
max=$(( 32768 / size * size ))
for ((i=size-1; i>0; i--)); do
while (( (rand=$RANDOM) >= max )); do :; done
rand=$(( rand % (i+1) ))
tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp
done
}
# Fill an array with values 1 to 99
array=({1..99});
# Shuffle the array at random
shuffle
# Echo shuffled array
echo ${array[#]}
Output
$ ./knuth
58 78 6 37 84 79 81 43 50 25 49 56 99 41 26 15 86 11 96 90 76 46 92 70 87 27 33 91 1 2 73 97 65 69 42 32 39 67 72 52 36 64 24 88 60 35 83 89 66 30 4 53 57 28 75 48 40 74 18 23 45 61 20 31 21 16 68 80 62 8 98 14 7 19 47 55 22 85 59 17 77 10 63 93 51 54 95 82 94 9 44 38 13 71 34 29 5 3 12
You can also use the -R switch to sort, if your version of sort supports it:
for x in {1..99} ; do echo $x ; done | sort -R

Resources