У меня есть .tsv
файл, содержащий информацию об источнике и месте назначения бакета s3. Я использую цикл while для чтения пути источника и места назначения из этого файла и выполнения s3 cp
операции. Обратите внимание, что файл содержит 100 тыс. строк.
Как мне использовать sed
команду, чтобы все исходные и целевые пути были заключены в двойные кавычки внутри файла ( xx.tsv
). Мне нужны двойные кавычки, потому что aws s3 не может обрабатывать имена файлов/папок, содержащие пробелы, без заключения их в ""
.
Я ищу что-то вроде ниже 3 строк будут изменены
s3://data01/repo01/image live01.png s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
к
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
решение1
Использование любого awk в любой оболочке на любой машине Unix:
$ awk -F'\t' -v OFS='"\t"' '{print "\"" $1, $2 "\""}' file
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
Вышеизложенное предполагает, что ни одно из имен ваших файлов не содержит символов табуляции, новой строки или двойных кавычек.
решение2
$ cat input.tsv
s3://data01/repo01/image live01.png s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
Примечание: столбцы разделяются символом табуляции, а не несколькими пробелами.
С sed
:
$ sed -E 's/^(s3:.*)\t+(s3:.*)/"\1"\t"\2"/' input.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
Использование \s+
или [[:blank:]]+
между двумя группами захвата вместо \t
тоже работает и дает идентичный результат. т.е.
sed -E 's/^(s3:.*)[[:blank:]]+(s3:.*)/"\1"\t"\2"/' input.tsv
и
sed -E 's/^(s3:.*)\s+(s3:.*)/"\1"\t"\2"/' input.tsv
Версия [[:blank:]]+
будет соответствовать одному или нескольким символам пробела или табуляции в качестве разделителя столбцов, в то время как версия \s+
будет соответствовать одному или нескольким символамлюбойпробельный символ (включая пробелы, табуляции и т. д.).
с awk
:
$ awk -F'\t' '{print "\"" $1 "\"\t\"" $2 "\""}' input.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
решение3
Обработка данных как CSV-файла, в котором в качестве разделителей полей используются символы табуляции:
csvformat -tT -U1 file.tsv >newfile.tsv
Это использует csvformat
изcsvkitдля чтения входных данных, разделенных табуляцией ( -t
), и создания выходных данных, разделенных табуляцией ( -T
), которые заключаются в кавычки ( -U1
) независимо от того, требует этого формат CSV или нет.
Обработка файла как CSV-файла и использование анализатора CSV для цитирования имеет то преимущество, что не приходится цитировать поля дважды, если они уже цитируются.
$ cat file.tsv
"s3://data01/repo01/image live01.png" s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
$ csvformat -tT -U1 file.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
Вы также, очевидно, могли бы просто прочитать данные как есть и добавить двойные кавычки при вызове s3 cp
. Я не знаю, как выглядит эта команда, но...
while IFS=$'\t' read -r src dst; do
s3 cp "\"$src\"" "\"$dst\""
done <file.tsv
решение4
Есть много способов почистить эту картошку, но я бы выбрал такой
sed 's;^\(s3://.*\) \(s3://.*\)$;"\1" "\2";' filename_in.tsv > out.tsv
который использует sed
регулярное выражение для применения к входным данным, захватывая все части строки «не пробелы между s3-URL», а затем заключая их в кавычки.
Надеюсь, тот, кто написал инструментарий, сгенерировавший .tsv, извлечет из этого урок — ошибка могла пойти необратимо, например, если бы в именах файлов были символы новой строки, что совершенно допустимо для имен файлов (на S3 это может быть не так, не проверял).
Хранение имен файлов в файлах с "чем угодно-разделителем" плохо кончится (если только этот разделитель не является нулевым байтом, который является практически единственным запрещенным байтом в именах файлов). Вам нужно экранирование или, что еще лучше, не храните длинные списки имен файлов в текстовых файлах, а используйте что-то простое для использования, например sqlite.