64

У меня довольно большой CSV-файл (75 МБ). Я просто пытаюсь составить график, поэтому мне не нужны все данные.

Переписывание: я хотел бы удалить n строк, затем оставить одну строку, затем удалить n строк и так далее.

Так что, если файл выглядел так:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6

и n = 2, тогда результат будет:

Line 3
Line 6

Кажется, что sed мог бы сделать это, но я не смог понять, как. Команда bash была бы идеальной, но я открыт для любого решения.

5 ответов5

112
~ $ awk 'NR == 1 || NR % 3 == 0' yourfile
Line 1
Line 3
Line 6

Переменная NR (количество записей) - это число записей, потому что поведение по умолчанию - новая строка для RS (разделитель записей). pattern и action являются необязательными в стандартном формате awk 'pattern {actions}' . когда мы даем только часть шаблона, awk записывает все поля $0 для true условий нашего шаблона.

51

sed также может сделать это:

$ sed -n '1p;0~3p' input.txt
Line 1
Line 3
Line 6

man sed объясняет ~ как:

первый шаг Шаг соответствует каждой строке шага, начиная с первой строки. Например, `` sed -n 1 ~ 2p '' напечатает все нечетные строки во входном потоке, а адрес 2 ~ 5 будет соответствовать каждой пятой строке, начиная со второй. первым может быть ноль; в этом случае sed работает так, как если бы он был равен шагу. (Это расширение.)

21

Perl может сделать это тоже:

while (<>) {
    print  if $. % 3 == 1;
}

Эта программа напечатает первую строку своего ввода, а затем каждую третью строку.

Чтобы объяснить это немного, <> является входной линией оператора, который перебирает входные линии , когда используется в цикле в while как это. Специальная переменная $. содержит количество прочитанных строк, а % является оператором модуля.

Этот код можно записать еще более компактно в виде однострочного текста, используя ключи -n и -e :

perl -ne 'print if $. % 3 == 1'  < input.txt  > output.txt

-e переключатель принимает фрагмент кода Perl для выполнения в качестве параметра командной строки, в то время как переключатель -n неявно оборачивает код в цикле в while как один показанный выше.


Редактировать: чтобы получить строки 1, 3, 6, 9, ... как в примере, а не строки 1, 4, 7, 10, ... как я впервые предположил, что вы хотели, замените $. % 3 == 1 с $. == 1 or $. % 3 == 0 .

7

Если вы хотите сделать это с помощью скрипта Bash, вы можете попробовать:

#!/bin/sh

echo Please enter the file name
read fname
echo Please enter the Nth lines that you want to keep
read n

exec<$fname
value=0
while read line
do
    if [ $(( $value % $n )) -eq 0 ] ; then
        echo -e "$line" >> new_file.txt
    fi
        let value=value+1 
done
echo "Check the 'new_file.txt' that has been created in this directory";

Сохраните его как «read_lines.sh» и не забудьте дать +x разрешений файлу bash.

chmod +x ./read_lines.sh
4

Решение в чистом bash, которое не порождает процесс:

{ for f in {1..2}; do read line; done;
  while read line; do
    echo $line;
    for f in {1..2}; do read line; done;
  done; } < file

Первая строка пропускает 2 строки в начале файла, а while печатается следующая строка и снова пропускает 2 строки.

Если ваш файл небольшой, это очень эффективный способ выполнить работу, так как он не запускает процесс. Когда ваш файл большой, следует использовать sed , так как он более эффективен в обработке io, чем bash .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .