Как удалить случайные строки из файла?

Да, вы можете обновить установку Wubi до 13.04, но поддержка Wubi была официально отключена Ubuntu , поэтому делать это не рекомендуется.

Хотя, как ни странно, 13.04 wubi.exe (подписано Canonical UK Ltd.) было опубликовано на http://releases.ubuntu.com/13.04 (по нераскрытым причинам). И нет, 13.04 wubi.exe не только создает гостевую учетную запись. Эта ошибка была исправлена.

Если вы решите выполнить обновление, которое обычно не рекомендуется при установке Wubi, просмотрите следующее: Обновление моего Wubi 11.04 до 11.10 Также учтите, что вы не сможете получить поддержку с этого сайта или с других сайтов. Сайты поддержки Ubuntu.

6
задан 15.04.2019, 19:14

4 ответа

Вы можете использовать цикл для получения случайного числа и команду sed для удаления строки.

for i in {0..5};
 do sed -i "$((1 + RANDOM % 10000))d" filename; 
done
6
ответ дан 25.10.2019, 15:43
  • 1
    {0..5} расширяется до 0 1 2 3 4 5, так что это удаляет шесть строк, вы, вероятно, имеете в виду {1..5}. Что еще более важно: что, если он пытается удалить, например, линия 10000 как вторая, или 9999 как третья ...? – cxw 14.04.2019, 19:15

С помощью gawk поместите следующий код в файл (называемый, скажем, del_random)

function randint(n)
{
    return int(n * rand()) + 1
}

BEGINFILE {
  command = sprintf("wc -l <\"%s\"", FILENAME)
  command | getline total_lines
  srand()
  delete arr
  while (length(arr) < lines_to_del)
  {
    val = randint(total_lines)
    if (val in arr)
       continue
    arr[val] = 1
  }
}
!(FNR in arr)

, а затем выполните его как

gawk -i inplace -f del_random lines_to_del=5 file1 lines_to_del=20 file2

Любое количество файлов может быть передано (file1, file2, ...) и количество строк, подлежащих удалению, может быть указано для каждого файла отдельно с помощью параметра lines_to_del, как показано. -i inplace является gawk эквивалентом sed -i

С другой стороны, если нужно удалить одинаковое количество строк из каждого файла, вы можете установить lines_to_del один раз следующим образом:

gawk -i inplace -v lines_to_del=5 -f del_random file1 file2
2
ответ дан 25.10.2019, 15:43

Аналогичен ответу Шивадити, но без цикла, и удалит строки из всего файла, а не только первые 10 строк:

sed -i "$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d;$((1+RANDOM%10000))d" filename

Выберет пять случайных чисел от 1 до 10000 и удалит эти строки в одиночная операция.

5
ответ дан 25.10.2019, 15:43
  • 1
    Что если два или более из этих случайных чисел совпадают? – aleroot 14.04.2019, 19:16

Вероятно, вы можете решить это более эффективно, чем с помощью цикла for, который должен обрабатывать весь файл один раз в строке для удаления.

filename="/PATH/TO/FILE"
number=5

line_count="$(wc -l < "$filename")"
line_nums_to_delete="$(shuf -i "1-$line_count" -n "$number")"
sed_script="$(printf '%dd;' $line_nums_to_delete)"

sed -i.bak -e "$sed_script" "$filename"

Или в одной строке (после определения переменных filename и number или их замены вручную):

sed -i.bak -e "$(printf '%dd;' $(shuf -i "1-$(wc -l < "$filename")" -n "$number"))" "$filename"

Переключатель -i.bak сообщает sed, что нужно редактировать / заменять входной файл немедленно, но сохраните резервную копию исходных данных, названную так же, как входной файл, но с добавленным к имени файла .bak Если вы не хотите, чтобы он делал копию, просто напишите -i.

Кстати, вам не нужно использовать переменные, как я. Вы также можете напрямую заменить "$number" и оба вхождения "$filename" на соответствующие значения. Я просто сделал это для ясности.


Чтобы разбить и объяснить оставшуюся часть команды:

sed -e "SCRIPT" "$filename"

запускает инструмент обработки текста sed для файла, указанного в переменной filename, применяя инструкции, заданные как SCRIPT Аргумент.

Наш SCRIPT динамически генерируется в строках над ним, которые запускают команды и присваивают свои выходы переменным. Здесь мы используем эти команды:

  • wc -l < "$filename" считывает файл, указанный в переменной filename, и выводит количество строк, содержащихся в этом файле.

    • В вашем случае это должно вернуть примерно 10000 в соответствии с размером, который вы указали в вопросе.
  • shuf -i "1-$line_count" -n "$number возвращает столько уникальных случайных чисел, сколько указано в переменной number в диапазоне от 1 до $line_count (включая обе границы).

    • Например, shuf -i 1-6 -n 2 будет подражать бросанию двух обычных шестигранных штампов.
  • printf '%dd;' ARGUMENTS возвращает форматированную строку, принимая все ARGUMENTS (на этот раз не в кавычках, чтобы рассматривать каждое случайное число как отдельный аргумент). Строка формата %dd; будет повторяться, пока остаются аргументы, а %d будет заменен аргументом, представленным в виде десятичного числа.

    • Следовательно, например, ввод 1 7 42 приведет к выводу 1d;7d;42d;.

Итоговый $sed_script, наконец, наш SCRIPT для sed. Простое число обрабатывается как адрес, то есть номер строки, к которой применяется действие, начиная с 1 для первой строки входного файла. d - это команда для удаления указанной строки, а ; разделяет несколько команд sed сценариев.

Все вместе, вся команда сначала проверяет ваш входной файл, как указано в переменной filename, и считает его строки. Затем он генерирует number множество уникальных случайных чисел в диапазоне от 1 до количества строк и из них создает скрипт sed для удаления каждой упомянутой случайной строки. Наконец, sed запускает этот скрипт в файле, модифицируя его.

14
ответ дан 25.10.2019, 15:43

Теги

Похожие вопросы