Что касается вашего первого вопроса «узнать, была ли подключена флэш-память 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
#
Предполагая, что текущий каталог содержит все файлы 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 отсутствуют -, я не буду пытаться придумать решение, которое это сделает.
Использование 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
.
Предыдущие ответы копируют данные и перезаписывают файлы. Этот метод должен сохранять те же индексы, не копировать и работать намного быстрее. Для каждого файла:
(a )Найдите длину каждого файла, прочитав первые 200 строк.
(b )Обрежьте файл до нужной длины, используя truncate
из GNU coreutils или с помощью truncate
, найденного в некоторых системах BSD:
SZ="$( head -n 200 -- "${file}" | wc -c )"
truncate -s "${SZ}" -- "${file}"
Я относительно новичок, так что будьте осторожны. Буду признателен за конструктивную обратную связь, если предлагаемое мной решение не является оптимальным.
Я создал 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
С 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 может содержать более одной строки (, встроенной в "..."
поля в кавычках ), вы можете использовать ksh93
read -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
Используйте 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