Объедините URL в bash с xargs

Я пытаюсь построить URL-адреса из вывода с одной записи в строке. Я попробовал это:

<stuff> | xargs -L1 -I {} echo "${url}&page=queryresults&j="{}

Однако для некоторых длинных строк (у них нет пробела, но могут быть тире и подчеркивания), я получаю '{}', где я ожидаю строку, сгенерированную <stuff>, Если я добавлю пробел между последней двойной кавычкой и {}, это сработает, но у меня есть лишний пробел, который мне не нужен:

<stuff> | xargs -L1 -I {} echo "${url}&page=queryresults&j=" {}

Точно так же, если я удаляю &page=queryresults немного, это работает. Понятия не имею почему.

Что мне здесь не хватает?

Это работает для этого:

blajob_123abcd_1234567890x

Но не это: SomeTask_some_long_project_name_with_cumulative_metrics_YYYYMMDD_2018_08_15T00_12345a67b8-scheduled-run-bla-bla-bla-yadda

1 ответ

Решение

Там нет необходимости для xargs здесь вообще, и тебе лучше без этого. Следующее гарантированно будет работать корректно на всех POSIX-совместимых оболочках:

while IFS= read -r line; do
  printf '%s&page=queryresults&j=%s\n' "$url" "$line"
done

Почему бы не придерживаться xargs -I {} echo "$url&...&j={}"?

  • xargs -IСпецификация включает в себя следующий текст: Сформированные аргументы не могут быть больше 255 байт. Если ваш URL длинный, это может привести к усечению, которое, по-видимому, соответствует описанным деталям.
  • xargs -I включено только в расширения XSI для POSIX; платформы, которые не претендуют на реализацию этих расширений, не обязаны предоставлять его или, если они это делают, вести себя как-то определенным образом.
  • Если вы использовали xargs printf "$url..." (подставляя URL в форматную строку, а не через заполнитель), у вас будут ошибки, если ваш URL содержит % приметы.
  • Если вы использовали echo, вы бы имели неопределенное поведение, если бы ваш URL содержал буквальную обратную косую черту (см. раздел ИСПОЛЬЗОВАНИЕ ПРИЛОЖЕНИЯ спецификации POSIX дляecho).

Тем не менее, если вы действительно хотите использовать xargsрассмотрим (в системах GNU):

xargs -d $'\n' printf "${url//%/%%}"'&page=queryresults&j=%s\n'

... или на платформе с инструментами BSD:

tr '\n' '\0' | xargs -0 printf "${url//%/%%}"'&page=queryresults&j=%s\n'

Замечания:

  • Потому что мы не используем -Iограничение в 255 символов не применяется вообще. (Так же, xargs способен передать столько аргументов каждому экземпляру /usr/bin/printf as будет соответствовать его командной строке, а не ограничиваться одним аргументом на вызов).
  • В URL мы заменяем любые % литералы с %%, Если URL-адрес уже правильно закодирован, он не должен содержать обратной косой черты (их уже следовало заменить на %5C).
  • Расширение GNU -d используется для указания того, что только новые строки должны рассматриваться как разделители между словами, которые должны рассматриваться как аргументы; это также предотвращает синтаксический анализ и использование буквальных кавычек xargs сам. На платформах BSD, преобразование новых строк в NUL и использование -0 служит заменой.
Другие вопросы по тегам