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

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

Как это сделать с cat, awk, cut и т. Д.?

вопрос задан 28.01.2010
Ruggiero Spearman
3545 репутация

19 ответов


  • 298 рейтинг

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

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

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

    ответ дан Joey, с репутацией 256017, 28.01.2010
  • 76 рейтинг

    Однострочный Perl будет простой версией решения Максима

    perl -MList::Util=shuffle -e 'print shuffle();' < myfile
    
    ответ дан Moonyoung Kang, с репутацией 761, 28.06.2011
  • 48 рейтинг

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

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

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


    • POSIX-совместимая функция на основе awk, sort и cut , адаптированная из собственного ответа OP :
    shuf() { awk 'BEGIN {srand(); OFMT="%.17f"} {print rand(), $0}' "$@" |
                   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))
    ' "$@"; }
    
    • Функция на основе Ruby , адаптированная из ответа Гофмана :
    shuf() { ruby -e 'Signal.trap("SIGPIPE", "SYSTEM_DEFAULT");
                         puts ARGF.readlines.shuffle' "$@"; }
    

    Сравнение производительности:

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

    Входной файл представляет собой файл на 1 миллион строк , созданный с использованием seq -f 'line %.0f' 1000000.
    Время указано в порядке возрастания (сначала самое быстрое):

    • shuf
      • 0.090s
    • рубин 2. 0. 0
      • 0.289s
    • Perl 5. 18. 2
      • 0.589s
    • Python
      • 1.342s с Python 2. 7. 6; 2.407s (! ) с Python 3. 4. 2
    • awk + sort + cut
      • 3.003s с BSD awk; 2.388s с GNU awk (4. 1. 1); 1.811s с mawk (1. 3. 4);

    Для дальнейшего сравнения, решения не упакованы как функции выше:

    • sort -R .
      • 10.661s - выделение большего количества памяти, кажется, не имеет значения
    • Scala
      • 24.229s
    • bash петель + sort
      • 32.593s

    Выводы :

    • Используйте shuf, если можете - это самый быстрый на сегодняшний день.
    • Ruby преуспевает, затем Perl .
    • Python заметно медленнее, чем Ruby и Perl, и, сравнивая версии Python, 2. 7. 6 немного быстрее, чем 3. 4. 1
    • Используйте POSIX-совместимое сочетание awk + sort + cut в качестве последнего средства ; какая реализация awk вы используете (mawk быстрее, чем GNU awk, BSD awk медленнее).
    • Держитесь подальше от sort -R, bash петель и Scala.
    ответ дан mklement0, с репутацией 113993, 8.05.2015
  • 27 рейтинг

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

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

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

    PS: Голосовал за «шуф», я понятия не имел, что было в coreutils в эти дни. , , вышеприведенное может все еще быть полезным, если в ваших системах нет 'shuf'.

    ответ дан NickZoic, с репутацией 4881, 28.01.2010
  • 17 рейтинг

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

    cat myfile | awk 'BEGIN{srand();}{print rand()"\t"$0}' | sort -k1 -n | cut -f2- > myfile.shuffled
    
    ответ дан Ruggiero Spearman, с репутацией 3545, 28.01.2010
  • 15 рейтинг

    вот сценарий awk

    awk 'BEGIN{srand() }
    { lines[++d]=$0 }
    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
    
    ответ дан ghostdog74, с репутацией 207471, 28.01.2010
  • 9 рейтинг

    Однострочник для 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's random.shuffle(). Это не будет хорошо работать со многими (более 2080) элементами.

    ответ дан scai, с репутацией 13403, 11.07.2013
  • 8 рейтинг

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

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

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

    any_command | shuffle
    

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

    Обновление:

    Обратите внимание, что умножение начальных нулей (%06d) и rand() позволяет ему работать должным образом и в системах, где sort не понимает числа. Можно отсортировать по лексикографическому порядку (а. к. а. нормальное сравнение строк).

    ответ дан Michał Šrajer, с репутацией 20364, 12.10.2011
  • 7 рейтинг

    Рубин FTW:

    ls | ruby -e 'puts STDIN.readlines.shuffle'
    
    ответ дан hoffmanc, с репутацией 476, 16.12.2014
  • 6 рейтинг

    Один вкладыш для Python, основанный на ответе 305399785 scai , но a) принимает stdin, b) делает результат повторяемым с помощью seed, c) выбирает только 200 всех строк.

    $ cat file | python -c "import random, sys; 
      random.seed(100); print ''.join(random.sample(sys.stdin.readlines(), 200))," \
      > 200lines.txt
    
    ответ дан dfrankow, с репутацией 8267, 22.07.2013
  • 3 рейтинг

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

    Установите пакет randomize-lines (homebrew), который имеет команду 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
    
    ответ дан Ahmad Awais, с репутацией 9004, 5.02.2017
  • 3 рейтинг

    Это скрипт на 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'
    
    ответ дан Jeff Wu, с репутацией 1790, 11.07.2013
  • 3 рейтинг

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

    sudo apt-get install randomize-lines
    

    Пример:

    Создайте упорядоченный список номеров и сохраните его до 1000. TXT:

    seq 1000 > 1000.txt
    

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

    rl 1000.txt
    
    ответ дан navigaid, с репутацией 250, 11.09.2016
  • 2 рейтинг

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

    Пример:

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

    the
    an
    linux
    ubuntu
    life
    good
    breeze
    

    Чтобы перетасовать линии, выполните:

    $ shuf words.txt
    

    , который выбрасывает перетасованные строки на стандартный вывод ; Таким образом, вы должны передать его в выходной файл , например:

    $ shuf words.txt > shuffled_words.txt
    

    Один такой тасованный пробег может дать:

    breeze
    the
    linux
    an
    ubuntu
    good
    life
    
    ответ дан kmario23, с репутацией 13275, 9.03.2018
  • 1 рейтинг

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

    ls -1 | scala -e 'for (l <- util.Random.shuffle(io.Source.stdin.getLines.toList)) println(l)'
    
    ответ дан swartzrock, с репутацией 681, 20.06.2014
  • 1 рейтинг

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

    shuf() {
    while read -r x;do
        echo $RANDOM$'\x1f'$x
    done | sort |
    while IFS=$'\x1f' read -r x y;do
        echo $y
    done
    }
    
    ответ дан Meow, с репутацией 2288, 22.01.2015
  • 0 рейтинг

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

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

      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
      
    ответ дан agc, с репутацией 4519, 17.04.2017
  • 0 рейтинг

    Другой вариант 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()] = $0;
    }
    
    END {
      for( k in lines ){
        print lines[k];
      }
    }
    
    ответ дан biziclop, с репутацией 12153, 1.12.2017
  • 0 рейтинг

    В Windows Вы можете попробовать этот командный файл , чтобы помочь вам перетасовать свои данные. TXT, использование кода партии

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

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

    Надеюсь, это поможет.

    ответ дан Ayfan, с репутацией 29, 27.04.2014