Как сохранить первые 200 строк всех CSV-файлов в каталоге с помощью bash?

Что касается вашего первого вопроса «узнать, была ли подключена флэш-память USB», ядро ​​сообщит о подключении запоминающих устройств USB.

Пример ниже, в котором предполагается, что ваш дистрибутив Linux используетsystemd(другие дистрибутивы могут вместо этого записывать в /var/log/messagesили аналогичный файл ).

# journalctl --since '2018-05-19' --until '2018-05-20' | grep 'kernel: usb'
May 19 12:22:15 localhost.localdomain kernel: usb 1-1.1.1: USB disconnect, device number 7
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: new high-speed USB device number 8 using ehci-pci
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: New USB device found, idVendor=13fe, idProduct=1f00
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: Product: Patriot Memory
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: Manufacturer:         
May 19 12:22:19 localhost.localdomain kernel: usb 1-1.1.1: SerialNumber: 07870CA23F48
May 19 12:22:19 localhost.localdomain kernel: usb-storage 1-1.1.1:1.0: USB Mass Storage device detected
#
10
13.01.2020, 14:03
6 ответов

Предполагая, что текущий каталог содержит все файлы CSV и все они имеют суффикс .csvимени файла:

for file in./*.csv; do
    head -n 200 "$file" >"$file.200"
done

При этом первые 200 строк каждого CSV-файла выводятся в новый файл с использованием headи перенаправления. Имя нового файла такое же, как и у старого, но с добавлением .200в конце имени. Нет проверки, существует ли уже новое имя файла или нет.

Если вы хотите заменить оригиналы:

for file in./*.csv; do
    head -n 200 "$file" >"$file.200" &&
    mv "$file.200" "$file"
done

&&в конце команды headделает так, что mvне будет запускаться, если с запуском headвозникли проблемы.

Если ваши CSV-файлы разбросаны по подкаталогам в текущем каталоге, используйте shopt -s globstar, а затем замените шаблон ./*.csvв цикле на ./**/*.csv. Это найдет любой CSV-файл в текущем каталоге или ниже и выполнит операцию над каждым. Шаблон подстановки **«рекурсивно» соответствует подкаталогам, но только если установлен параметр оболочки globstar.


Для CSV-файлов, содержащих данные со встроенными символами новой строки, описанное выше не будет работать должным образом, поскольку вы можете обрезать запись. Вместо этого вам придется использовать какой-нибудь инструмент, поддерживающий CSV -, который сделает эту работу за вас.

Далее используется CSVkit, набор инструментов командной строки -для синтаксического анализа и общей работы с CSV-файлами, вместе с jq, инструментом для работы с файлами JSON.

В комплекте CSV нет инструмента, который может обрезать CSV-файл в определенной точке, но мы можем преобразовать CSV-файлы в JSON и использовать jqдля вывода только первых 200 записей:

for file in./*.csv; do
    csvjson -H "$file" | jq -r '.[:200][] | map(values) | @csv' >"$file.200" &&
    mv "$file.200" "$file"
done

Учитывая некоторый CSV-файл, подобный приведенному ниже короткому примеру,

a,b,c
1,2,3
"hello, world",2 3,4
"hello
there","my good
man",nice weather for ducks

команда csvjsonвыдаст

[
  {
    "a": "a",
    "b": "b",
    "c": "c"
  },
  {
    "a": "1",
    "b": "2",
    "c": "3"
  },
  {
    "a": "hello, world",
    "b": "2 3",
    "c": "4"
  },
  {
    "a": "hello\nthere",
    "b": "my good\nman",
    "c": "nice weather for ducks"
  }
]

Инструмент jqзатем примет это и для каждого объекта в массиве (, ограниченном первыми 200 объектами ), извлечет значения в виде массива и отформатирует его как CSV.

Вероятно, это преобразование можно выполнить напрямую с помощью csvpy, другого инструмента в CSVkit, но поскольку мои навыки работы с Python отсутствуют -, я не буду пытаться придумать решение, которое это сделает.

42
27.01.2020, 19:59

Использование sed с подстановкой оболочки:

sed -ni '1,200p' *.csv

Использование подстановки/sed/parallel:

printf '%s\n' *.csv | parallel -- sed -ni '1,200p' {}

Это найдет все .csvфайлы в текущем каталоге и передаст их в GNU parallel, который выполнит над ними команду sed, чтобы сохранить только первые 200 строк. Обратите внимание, что это приведет к перезаписи файлов на месте.

Или с помощью параллельной головки:

printf '%s\n' *.csv | parallel -- head -n 200 {} ">" {}.out

При этом будут созданы новые файлы с суффиксом .out.

15
27.01.2020, 19:59

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

(a )Найдите длину каждого файла, прочитав первые 200 строк.

(b )Обрежьте файл до нужной длины, используя truncateиз GNU coreutils или с помощью truncate, найденного в некоторых системах BSD:

SZ="$( head -n 200 -- "${file}" | wc -c )"
truncate -s "${SZ}" -- "${file}"
25
27.01.2020, 19:59

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

Я создал 4 примера файлов с номерами от 1 до 4, например. touch {1..4}и каждый файл содержит 10 строк образцов, например, в первом файле, и строки с 11 по 20 в следующем файле и т. д.

Файл 1

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10 

Файл 2

Line 11
Line 12
Line 13
Line 14
Line 15
Line 16
Line 17
Line 18
Line 19
Line 20

Чтобы извлечь первые 2 строки в качестве примера (, которые можно экстраполировать до 200 ), команда head -n 2 {1..4}возвращает результат;

==> 1 <==
Line 1
Line 2

==> 2 <==
Line 11
Line 12

==> 3 <==
Line 21
Line 22

==> 4 <==
Line 31
Line 32

Команда может перенаправить вывод в другой файл с помощью командыhead -n 2 {1..4} > ExtractedOutput

1
27.01.2020, 19:59

С ksh93 и совместимой с POSIX headреализацией (, которая оставляет курсор внутри стандартного ввода сразу после последней выводимой строки ), вы можете сделать:

for file in ~(N)./*; do
  [ -f "$file" ] || continue # skip non-regular files
  head -n 200 0<>; "$file" > /dev/null
done

Оператор перенаправления <>;представляет собой вариант стандартного оператора <>, который усекает файл на месте после возврата перенаправленной команды при условии, что команда возвращает статус успешного завершения.

Здесь мы отбрасываем вывод head, нас просто интересует его способность оставлять курсор сразу после 200-й строки.

К сожалению, встроенная функцияhead(ksh93, которая активируется, если вы вводите builtin headили если /opt/ast/binпредшествует любому каталогу с командой headв нем в $PATH), не ведет себя в соответствии с POSIX в этом случае. Он считывает ввод порциями (, как и большинство других headреализаций ), но не беспокоит поиском конца 200-й строки при вызове таким образом. Чтобы заставить его выполнить поиск назад, нам нужно выполнить внешнюю команду, которая в первую очередь противоречит цели наличия встроенной head:

builtin head # enable ksh93's head builtin
{ head -n 200 && /bin/true; } 0<>; file > /dev/null

Другим рабочим подходом, не требующим вызова внешней утилиты, является явный поиск смещения 0 -после возврата head:

builtin head # enable ksh93's head builtin
for file in ~(N)./*; do
  [ -f "$file" ] || continue # skip non-regular files
  { head -n 200 && exec <#((CUR)); } 0<>; "$file" > /dev/null
done

Для ввода в формате CSV, а также для сохранения первых 200 записей CSV (в отличие от строк, поскольку запись CSV может содержать более одной строки (, встроенной в "..."поля в кавычках ), вы можете использовать ksh93read -Sспециально разработан для чтения CSV в цикле:

for file in ~(N)./*.csv; do
  [ -f "$file" ] || continue # skip non-regular files
  for ((i=0;i<200;i++)); do 
    IFS=, read -rSA discard
  done 0<>; "$file"
done
3
27.01.2020, 19:59

Используйте ed, чтобы обрезать каждый файл.

for f in *.csv; do
  printf '201,$d\nwq\n' | ed "$f"
done

Если вы хотите сохранить резервную копию, проще использовать ex. (Вы также можете счесть exболее простым в использовании, несмотря ни на что; просто отпустите w!%.bak|, чтобы не создавать резервную копию.)

for f in *.csv; do
    ex -c 'w!%.bak|201,$d|wq' "$f"
done
1
27.01.2020, 19:59

Теги

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