У меня есть файл, который содержит 10000 строк, и я хочу удалить из него 5 случайно определенных строк. Как я могу это сделать?
Вы можете использовать цикл для получения случайного числа и команду sed для удаления строки.
for i in {0..5};
do sed -i "$((1 + RANDOM % 10000))d" filename;
done
Ответ на U & amp; L имеет это хорошее awk
решение проблемы:
<file awk -v p=5 -v n=$(<file wc -l) '
BEGIN {srand()}
rand() * n-- < p {p--; next}
{print}'
-v p=5
- множество переменная p
, содержащая количество удаляемых строк -v n=$(<file wc -l)
- установить переменную n
, содержащую количество строк в файле BEGIN {srand()}
- перед обработкой файла установить затравка для генерации случайных чисел, это обязательное условие для использования rand()
для получения действительно ™ случайных чисел rand() * n-- < p {…}
- Условное выражение, запускающее деталь в фигурных скобках, если оно истинно. rand()
создает случайное число между (включая) 0 и (исключая) 1, оно умножается на количество строк n
, которое уменьшается на 1. Если результат меньше, чем p
, выражение является истинным. p--; next
- уменьшить p
на 1 и перейти к следующей строке, игнорируя последующие команды print
- напечатать текущую обработанную строку Вторая и последняя строка сценария awk
запускается для каждой строки входного файла, поэтому в каждой строке есть шанс p / n
пропустить и не распечатать строку, в то время как действие по умолчанию - просто напечатать строку. 1135]
Я создал файл с буквами a – e, каждая в отдельной строке, с помощью
printf '%s\n' {a..e} >file
и установил p=1
для случайного удаления одной строки. Я изменил код, чтобы также печатать значения n
и p
для каждой строки, прежде чем уменьшится какое-либо из них.
$ <file awk -v n=$(<file wc -l) -v p=1 'BEGIN {srand()} {printf "n="n" p="p" "} rand() * n-- < p {p--; print ""; next} {print}'
n=5 p=1
n=4 p=0 b
n=3 p=0 c
n=2 p=0 d
n=1 p=0 e
$ <file awk -v n=$(<file wc -l) -v p=1 'BEGIN {srand()} {printf "n="n" p="p" "} rand() * n-- < p {p--; print ""; next} {print}'
n=5 p=1 a
n=4 p=1 b
n=3 p=1
n=2 p=0 d
n=1 p=0 e
$ <file awk -v n=$(<file wc -l) -v p=1 'BEGIN {srand()} {printf "n="n" p="p" "} rand() * n-- < p {p--; print ""; next} {print}'
n=5 p=1 a
n=4 p=1 b
n=3 p=1 c
n=2 p=1 d
n=1 p=1
Аналогичен ответу Шивадити, но без цикла, и удалит строки из всего файла, а не только первые 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 и удалит эти строки в одиночная операция.
С помощью 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
Вероятно, вы можете решить это более эффективно, чем с помощью цикла 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
, и выводит количество строк, содержащихся в этом файле.
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
запускает этот скрипт в файле, модифицируя его.