При объединении tr с нулевыми символами и xargs -0 это не работает должным образом

Итак, у меня есть файл, содержащий поля с разделителями ~, которые мне нужно преобразовать в sql. Загвоздка здесь в том, что в этих данных есть пробелы. Как правило, это не было бы проблемой, потому что я мог бы просто использовать xargs -0 и передать ему нулевые разделители.

Когда я соединяю его с tr '~' '\0000', я веду себя странно, и я не знаю, почему. Кажется, что при использовании xargs на самом деле требуется слишком много полей.

Вход:

FA_PRD01_PHX1~EBDT~30-JAN-2023~18~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS~1~1
FA_PRD01_PHX1~EBDT~30-JAN-2023~08~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW~1~1
FA_PRD01_PHX1~EBDT~23-JAN-2023~18~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS~1~1
FA_PRD01_PHX1~EBDT~23-JAN-2023~08~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW~1~1
FA_PRD01_PHX1~EBDT~13-MAR-2023~04~JobDefinition://company/apps/ess/custom/shared/Apps_Reports/Certifications and Competencies/ALLCERTRPT~1~1
FA_PRD01_PHX1~EBDT~13-FEB-2023~18~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS~1~1
FA_PRD01_PHX1~EBDT~13-FEB-2023~08~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW~1~1
FA_PRD01_PHX1~EBDT~13-FEB-2023~05~JobDefinition://company/apps/ess/custom/shared/Apps_Reports/Certifications and Competencies/ALLCERTRPT~1~1
FA_PRD01_PHX1~EBDT~06-FEB-2023~18~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS~1~1
FA_PRD01_PHX1~EBDT~06-FEB-2023~08~JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW~1~1

команда:

cat data.txt | tr '~' '\0000' | 
   xargs -0 -n 7 printf "insert into ESS_SYSTEM_ERROR_METRICS  values('%s','%s',to_date('%s','DD-MM-YYYY'),%s,'%s',%s,%s);\n"

ожидал:

insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),18,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS',1,1);

действительный:

insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),18,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS',1,1
FA_PRD01_PHX1);
insert into ESS_SYSTEM_ERROR_METRICS  values('EBDT','30-JAN-2023',to_date('08','DD-MM-YYYY'),JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW,'1',1
FA_PRD01_PHX1,EBDT);

Мой счетчик полей с xargs правильный, поэтому мне также интересно, использует ли xargs что-то еще для разграничения.

использовать awk -F~ '{printf("insert ... %s.....%s\n", $1, $2... $7)' вместо этого? (тоже не нужно xargs(?) Удачи.

shellter 30.03.2023 23:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
97
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

xargs использует нулевой байт для разграничения, как вы сказали. Это не разграничивает новые строки.

В очень упрощенном примере, если у вас есть эти две строки (где 0 — ноль):

a0b0c0d\n
e0f0g0h\n

Четвертый токен — это не просто d, это d\ne, потому что xargs читается до следующего нулевого байта.

Что-то вроде этого должно работать:

while IFS='~' read -ra line ; do
  printf '%s\0' "${line[@]}"
done < data.txt | xargs -0 -n 7 printf "insert into ESS_SYSTEM_ERROR_METRICS  values('%s','%s',to_date('%s','DD-MM-YYYY'),%s,'%s',%s,%s);\n"

нет необходимости в \0 + xargs в этом случае; можно передать массив прямо в нужный printf внутри цикла: while IFS='~' read -ra line; do printf "insert into ...." "${line[@]}"; done < data.txt

markp-fuso 31.03.2023 00:03
Ответ принят как подходящий

Поскольку вы заменяете ~ символом \0 и используете \0 в качестве разделителя для xargs, \n во входных данных будет рассматриваться как часть последнего «поля»; вам также нужно перевести новые строки на входе:

tr '\n~' '\0' < data.txt |
xargs -0 -n 7 printf "insert into ESS_SYSTEM_ERROR_METRICS  values('%s','%s',to_date('%s','DD-MM-YYYY'),%s,'%s',%s,%s);\n"

совет: при автоматической генерации кода вам лучше правильно экранировать строки (здесь вы печатаете их RAW, это может оказаться опасным)


ОБНОВЛЯТЬ

Под правильным экранированием я подразумеваю генерацию SQL таким образом, чтобы не допустить внедрения кода; например:

awk -F'~' '
    function sql_stringify(str,escape_backslashes) {
        gsub(/\047/,"\047\047",str);
        if (escape_backslashes)
            gsub(/\/,"\\\\&",str);
        return "\047" str "\047";
    }
    {
        printf( "insert into ESS_SYSTEM_ERROR_METRICS  " );
        printf( "values(%s,%s,to_date(%s,%s),%d,%s,%d,%d);\n", \
            sql_stringify($1), \
            sql_stringify($2), \
            sql_stringify($3), \
            sql_stringify("DD-MM-YYYY"), \
            $4, \
            sql_stringify($5), \
            $6, \
            $7 \
       );
    }
' data.txt

note: for MySQL and PostgreSQL you'll need to set the escape_backslashes switch of sql_stringify to true

Я решил использовать %s вместо %d, потому что printf считает, что 09 следует интерпретировать как восьмеричное.

Christian Bongiorno 31.03.2023 01:12

Поскольку xargs рассматривает \0 как разделитель, \n становится частью данных. В идеале нам также нужно преобразовать \n в \0. В качестве альтернативы ...

Мы можем сохранить разделитель ~ и преобразовать \n в ~:

$ head -2 data.txt | tr '\n' '~' | xargs -d~ -n 7 printf "insert into ESS_SYSTEM_ERROR_METRICS  values('%s','%s',to_date('%s','DD-MM-YYYY'),%s,'%s',%s,%s);\n"
insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),18,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS',1,1);
insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),08,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW',1,1);

Альтернативная идея с использованием awk:

$ awk -F'~' -v qt = "'" '{printf "insert into ESS_SYSTEM_ERROR_METRICS  values(%s,%s,to_date(%s,%s),%s,%s,%s,%s);\n",qt $1 qt,qt $2 qt,qt $3 qt,qt "DD-MM-YYYY" qt, $4,qt $5 qt,$6,$7 }' data.txt
insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),18,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLS',1,1);
insert into ESS_SYSTEM_ERROR_METRICS  values('FA_PRD01_PHX1','EBDT',to_date('30-JAN-2023','DD-MM-YYYY'),08,'JobDefinition://company/apps/ess/custom/Shared Folders/Apps_Reports/APPSSALESFORCETIMEDTLSNEW',1,1);
... snip ...

Конечно, в этом конкретном случае это немного излишне, но кое-что следует иметь в виду, если / когда вы столкнетесь с некоторыми сложными проблемами форматирования, которые трудно (или) решить с помощью только tr/xargs, ymmv ...

xargs -d плохо поддерживается
Fravadona 31.03.2023 00:45
-d не поддерживается на вашем Mac.
Christian Bongiorno 31.03.2023 01:07

Я не знал, что xargs по-прежнему будет использовать \n в качестве разделителя, если я скажу это -0, это была моя ошибка

Christian Bongiorno 31.03.2023 01:14

Другие вопросы по теме