Как я могу тасовать строки текстового файла в командной строке Unix или в shell-скрипт?



Я хочу перемешать строки текстового файла случайным образом и создать новый файл. Файл может содержать несколько тысяч строк.



как я могу сделать это с cat,awk,cut и т. д.?

692   19  

19 ответов:

можно использовать shuf. По крайней мере, на некоторых системах (похоже, не в POSIX).

как jleedev указал: sort -R также может быть вариант. По крайней мере, в некоторых системах; ну, вы получите картину. было указано это sort -R на самом деле не перетасовывает, а сортирует элементы в соответствии с их хэш-значением.

[Примечание редактора: sort -Rпочти тасует, за исключением того, что дублировать строки / сортировка ключей всегда заканчивается рядом друг с другом. Другими словами: только с уникальный входные линии / клавиши-это настоящая перетасовка. Хотя это правда, что порядок вывода определяется хэш-значения, случайность происходит от выбора случайного хэша функции - см. руководство.]

Perl one-liner будет простой версией решения Максима

perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' < myfile

этот ответ дополняет многие великие существующие ответы следующим образом:

  • существующие ответы упаковано в гибкий функции оболочки:

    • функции не только stdin ввод, но в качестве альтернативы также filename аргументы
    • функции примите дополнительные меры для обработки SIGPIPE обычным способом (тихо завершение с кодом выхода 141), в отличие от шумного разрыва. Это важно, когда функция выводится по трубопроводу в трубу, которая закрыта рано, например, при трубопроводе в head.
  • A сравнение производительности сделано.


  • POSIX-совместимыми}' "$@" | sort -k1,1n | cut -d ' ' -f2-; }
    shuf() { perl -MList::Util=shuffle -e 'print shuffle(<>);' "$@"; }
    
    • Python-основанная функция, приспособленная от scai по:
    shuf() { python -c '
    import sys, random, fileinput; from signal import signal, SIGPIPE, SIG_DFL;    
    signal(SIGPIPE, SIG_DFL); lines=[line for line in fileinput.input()];   
    random.shuffle(lines); sys.stdout.write("".join(lines))
    ' "$@"; }
    
    shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                         puts ARGF.readlines.shuffle' "$@"; }
    

    для сравнения:

    примечание: эти цифры были получены на конце 2012 года iMac с 3,2 ГГц Intel Core i5 и Fusion Drive, под управлением OSX 10.10.3. в то время как тайминги будут варьироваться в зависимости от используемой ОС, спецификации машины, awk реализации (например, BSD awk версия, используемая на OSX, обычно медленнее, чем GNU awk и особенно mawk),это должно дать общее чувство относительные производительность.

    Input

Я использую крошечный скрипт perl, который я называю "unsort":

#!/usr/bin/perl
use List::Util 'shuffle';
@list = <STDIN>;
print shuffle(@list);

У меня также есть версия с нулевыми разделителями, называемая "unsort0" ... удобный для использования с find-print0 и так далее.

PS: проголосовали за " Шуф " тоже, я понятия не имел, что было в coreutils в эти дни ... вышеизложенное может быть полезно, если в ваших системах нет "shuf".

вот первая попытка, которая легко на кодере, но трудно на процессоре, который добавляет случайное число к каждой строке, сортирует их, а затем удаляет случайное число из каждой строки. По сути, строки сортируются случайным образом:

cat myfile | awk 'BEGIN{srand();}{print rand()"\t"}' | sort -k1 -n | cut -f2- > myfile.shuffled

вот скрипт awk

awk 'BEGIN{srand() }
{ lines[++d]= }
END{
    while (1){
    if (e==d) {break}
        RANDOM = int(1 + rand() * d)
        if ( RANDOM in lines  ){
            print lines[RANDOM]
            delete lines[RANDOM]
            ++e
        }
    }
}' file

выход

$ cat file
1
2
3
4
5
6
7
8
9
10

$ ./shell.sh
7
5
10
9
6
8
2
1
3
4

один лайнер для python:

python -c "import random, sys; lines = open(sys.argv[1]).readlines(); random.shuffle(lines); print ''.join(lines)," myFile

и для печати только одной случайной строки:

python -c "import random, sys; print random.choice(open(sys.argv[1]).readlines())," myFile

но вижу этот пост для устранения недостатков в Python random.shuffle(). Он не будет хорошо работать со многими (более 2080) элементами.

простая awk-функция сделает работу:

shuffle() { 
    awk 'BEGIN{srand();} {printf "%06d %s\n", rand()*1000000, ;}' | sort -n | cut -c8-
}

использование:

any_command | shuffle

Это должно работать практически на любом UNIX. Протестировано на Linux, Solaris и HP-UX.

обновление:

обратите внимание, что ведущие нули (%06d) и rand() умножение делает его работать должным образом также на системах, где sort не понимаю цифр. Он может быть отсортирован по лексикографическому порядку (a.k.a. normal string compare).

Ruby FTW:

ls | ruby -e 'puts STDIN.readlines.shuffle'

один лайнер для Python на основе scai по, но а) принимает stdin, Б) делает результат повторяемым с семенем, в) выбирает только 200 из всех строк.

$ cat file | python -c "import random, sys; 
  random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
  > 200lines.txt

это скрипт python, который я сохранил как rand.py в моей домашней папке:

#!/bin/python

import sys
import random

if __name__ == '__main__':
  with open(sys.argv[1], 'r') as f:
    flist = f.readlines()
    random.shuffle(flist)

    for line in flist:
      print line.strip()

на Mac OSX sort -R и shuf недоступны, так что вы можете псевдоним это в вашем bash_profile как:

alias shuf='python rand.py'

у нас есть пакет, чтобы сделать саму работу:

sudo apt-get install randomize-lines

пример:

создайте упорядоченный список чисел и сохраните его до 1000.txt:

seq 1000 > 1000.txt

чтобы перетасовать его, просто используйте

rl 1000.txt

если, как я вы пришли сюда, чтобы искать альтернативный shuf для macOS затем используйте randomize-lines.

установить randomize-lines(самогон) пакет, который имеет rl команда, которая имеет аналогичную функциональность shuf.

brew install randomize-lines

Usage: rl [OPTION]... [FILE]...
Randomize the lines of a file (or stdin).

  -c, --count=N  select N lines from the file
  -r, --reselect lines may be selected multiple times
  -o, --output=FILE
                 send output to file
  -d, --delimiter=DELIM
                 specify line delimiter (one character)
  -0, --null     set line delimiter to null character
                 (useful with find -print0)
  -n, --line-number
                 print line number with output lines
  -q, --quiet, --silent
                 do not output any errors or warnings
  -h, --help     display this help and exit
  -V, --version  output version information and exit

простой и интуитивно понятный способ будет использовать shuf.

пример:

предположим words.txt как:

the
an
linux
ubuntu
life
good
breeze

чтобы перетасовать строки, сделайте:

$ shuf words.txt

который бы бросает перетасованные строки в стандартный вывод; Итак, вы труба до выходной файл как:

$ shuf words.txt > shuffled_words.txt

один такой shuffle run может выход:

breeze
the
linux
an
ubuntu
good
life

Если у Вас установлен Scala, вот один лайнер для перетасовки ввода:

ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'

эта функция bash имеет минимальную зависимость(только сортировка и bash):

shuf() {
while read -r x;do
    echo $RANDOM$'\x1f'$x
done | sort |
while IFS=$'\x1f' read -r x y;do
    echo $y
done
}

в windows вы можете попробовать этот пакетный файл чтобы помочь вам перетасовать ваши данные.txt, использование пакетного кода

C:\> type list.txt | shuffle.bat > maclist_temp.txt

после выполнения этой команды, maclist_temp.txt будет содержать рандомизированный список строк.

надеюсь, что это помогает.

пока не упоминается:

  1. The unsort util. Синтаксис (несколько ориентированный на плейлист):

    unsort [-hvrpncmMsz0l] [--help] [--version] [--random] [--heuristic]
           [--identity] [--filenames[=profile]] [--separator sep] [--concatenate] 
           [--merge] [--merge-random] [--seed integer] [--zero-terminated] [--null] 
           [--linefeed] [file ...]
    
  2. msort можно перетасовать по строке, но это обычно перебор:

    seq 10 | msort -jq -b -l -n 1 -c r
    

другое awk вариант:

#!/usr/bin/awk -f
# usage:
# awk -f randomize_lines.awk lines.txt
# usage after "chmod +x randomize_lines.awk":
# randomize_lines.awk lines.txt

BEGIN {
  FS = "\n";
  srand();
}

{
  lines[ rand()] = ;
}

END {
  for( k in lines ){
    print lines[k];
  }
}

Comments

    Ничего не найдено.