Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I have a text file and I want to delete random lines from a range. Here is an example:

Line 1: abcd

Line 2: efgh

Line 3: ijkl

Line 4: mnop

Line 5: qrst

Line 6: uvwxyz

Out of these six, I want to randomly delete, say, 3.

How to get that done? It would be great if there is a solution in vim, so one can apply it on different ranges.

share|improve this question
add comment

3 Answers

up vote 3 down vote accepted

Here's a solution using sed:

sed -i $((start + RANDOM % range))d filename.txt

where:

  • start is the beginning line number of your range
  • range (or end-start is the number of lines to include from start)
  • sed -i -Nd tells sed to delete line N in the input file
  • RANDOM is bash's random number generator; a special shell variable that holds a random integer between 0 and 32767 when you use it.

So, for example, to delete a random line between lines 90 and 120 in file test.txt, you'd use:

sed -i $((90 + RANDOM % 30))d test.txt
share|improve this answer
    
Great! Almost there. Just three more points: What if I want to delete multiple random lines at one go? Can I tell sed to delete say, m lines? Can I tell sed to keep x number of line? Lastly, if I want to execute the same command on a range in vim, :[range] !sed .... what should follow? –  deshmukh Jul 13 '12 at 5:46
    
To delete a range N starting or ending at a random line, simply prefix N, or suffix ,N to the sed expression. To delete multiple random lines, you can repeat the sed expression with -e i.e. sed -e $... -e $... -e $.... Keeping a certain number of lines seems difficult to do with a one-liner, but certainly with a bash script... –  izx Jul 13 '12 at 6:18
    
Please avoid using the $[ ... ] syntax. It has been deprecated for a decade and it was removed from the bash documentation ages ago. The only reason it still works is because of bash's policy on backward compatibility. $(( )) is the documented syntax for arithmetic expansion. printf '%s\n' "$((90 + RANDOM % 30))d" w | ed -s file.txt –  geirha Jul 13 '12 at 10:31
    
OK. This was perfect. I have added an answer by putting everything together. –  deshmukh Jul 14 '12 at 4:21
    
@geirha: many thanks for the edit. I missed your initial comment notification. –  izx Jul 15 '12 at 8:14
add comment

Use the following command

:nd

where n is the line number.

share|improve this answer
    
That would just delete a specific line. I want to delete a random line. –  deshmukh Jul 13 '12 at 5:47
add comment

In order to delete multiple random lines form a specific range in the text file, here is what I did:

  • Open the file in vim
  • Go to the top of the range from where you want to remove multiple random lines. The range should have an empty line at the bottom
  • Enter the following command:

    .,/^\s*$/-1 !sed -e $((9 * $RANDOM / 32267))d
    

. - From here

,/^\s*$/-1 - Till the last non-blank line

!sed -e $((9 * $RANDOM / 32267))d - the sed command to delete a random line

That will delete one line at random.

Now, if you want to delete 5 more random lines, just do 5@: and vim does the rest.

This can be further improved if I can replace that 9 (number of lines from which to delete) with some expression that will be universal

share|improve this answer
1  
bash only does integer math, so $((9 * RANDOM / 32267)) will only result in 0 or 9. You really do need modulo. $((RANDOM%9)) –  geirha Jul 14 '12 at 10:02
1  
Here's an awk that reads the input into an array, then prints all but one random line from the array. !awk '{a[NR]=$0}END{srand();r=int(NR*rand())+1;for(i=1;i<=NR;++i)if(i\!=r)print a[i]}' –  geirha Jul 14 '12 at 11:15
    
@geirha Thanks! I will still use the same 4@: technique to delete multiple lines in vim. But I wonder how can I print all but 'n' random lines using awk –  deshmukh Jul 15 '12 at 6:02
1  
That's a bit more complex since you now have to keep track of what lines you've omitted already. Instead of making r an int we'll make it an array, and fill it with random numbers until it has n unique ones. awk '{a[NR]=$0}END{srand();r[int(NR*rand())+1];while(length(r)<(n<NR?n:NR))r[int(NR*‌​rand())+1];for(i=1;i<=NR;++i)if(\!(i in r))print a[i]}' n=2 n=2 at the end says to omit two lines. –  geirha Jul 15 '12 at 8:08
1  
Ah, sorry, I forgot mawk's length() function only works on strings, not arrays. I only tested it with gawk. Is gawk (GNU awk) an option? –  geirha Jul 23 '12 at 15:26
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.