Я бы не стал использовать --delete-after
, потому что это заставляет rsync повторно сканировать список файлов.
Лучшим вариантом на сегодняшний день является использование --delete-during
(или --del
для краткости). Если вы хотите сохранить эффект "удаления после" из-за проблем с ошибками ввода-вывода, используйте --delete-delay
.
См. man-страницу для справки:
Некоторые опции требуют, чтобы rsync знал полный список файлов, поэтому эти опции отключают режим инкрементной рекурсии. К ним относятся: --delete-before, --delete-after, --prune-empty-dirs и --delay-updates. В связи с этим, режим удаления по умолчанию, когда вы указываете --delete, теперь --delete-during, когда оба конца не ниже 3.0.0 (используйте --del или --delete-during, чтобы запросить этот улучшенный режим удаления в явном виде). Смотрите также опцию --delete-delay опция, которая является лучшим выбором, чем использование --delete-after.
И, конечно, соответствующие разделы для каждого метода.
Поскольку ваши данные разделены и легко читаются, есть несколько способов сделать это. Sed может разобрать ваши данные в одной строке и вывести изменения:
sed -r -i 's/^(.*):(.*):(.*):(.*):(.*)$/{"randomId":{"s":"\1"},"id":{"s":"\2"},"userId":{"s":"\3"},"dns":{"s":"\4"},"status":{"s":"\5"}}/' input.txt
Вы используете группы захвата, чтобы захватить все между началом файла, вашим разделителем и концом файла, а затем просто манипулируете текстом вокруг этих групп. Каждая группа захвата обозначается "\#", где # - номер группы захвата, начиная с единицы и увеличиваясь на единицу для каждой группы.
Как уже упоминалось, вы также можете установить свой собственный разделитель. Bash имеет встроенную переменную под названием IFS (внутренний разделитель полей). По умолчанию IFS - пробел, но у вас есть возможность изменить ее. Я не буду показывать пример bash, так как он уже приводился и будет просто копией.
perl -F: -pale '
@A = qw/randomId id userId dns status/;
($k, $_) = (0, "{" . join(",", map qq/"$A[$k++]":{"s":"$_"}/, @F) . "}");
' yourfile
@F
содержит разделенные поля на :
, которые затем сшиваются вместе с соответствующим массированием {"s": "fieldI"}
и снабжены префиксом соответствующего элемента из массива @A
. Все эти элементы объединены соединением
на ,
и заключены в "{" ... "}". И вы сделали.
Этот блок grep/echo не сделает ничего полезного; $? будет установлен один раз - он не будет перебирать поля.
К счастью, оказывается, есть гораздо более простой способ сделать это: просто разделить поля на переменные. К счастью, read
может сделать это за вас:
while IFS=':' read -r randomid id userid dns status; do
printf '{"randomId":{"s":"%s"},"id":{"s":"%s"},"userId":{"s":"%s"},"dns":{"s":"%s"},"status":{"s":"%s"}}\n' \
"$randomid" "$id" "$userid" "$dns" "$status"
done
Использование printf
вместо более привычного echo
позволяет избежать всех \"
-последовательностей, которые требует echo
. Обратите внимание на обратную косую черту в конце строки, чтобы разделить ее.
BTW: Формат, который вы создаете, называется JSON, и могут существовать инструменты для его генерации (например, jq). Кроме того, он может потребовать собственного экранирования, если, например, ваши поля могут содержать двойные кавычки.
С perl
:
perl -MJSON -F: -ple '@A = qw/randomId id userId dns status/; $_ = encode_json({map { shift @A => { "s" => $_ } } @F } )' input.csv