xargs - додайте кожен аргумент до параметра


Відповіді:


13

Один із способів зробити це:

echo "a b c" | xargs printf -- '-f %s\n' | xargs mycommand

Це передбачає a, bі cне містять пробілів, нових рядків, цитат чи зворотних рисочків. :)

З GNU findutilви можете впоратися із загальним випадком, але це трохи складніше:

echo -n "a|b|c" | tr \| \\0 | xargs -0 printf -- '-f\0%s\0' | xargs -0 mycommand

Ви можете замінити |роздільник з яким - або іншим символом, який не з'являється в a, bабо c.

Редагувати: Як зазначає @MichaelMol , дуже довгий список аргументів є ризиком переповнення максимальної довжини аргументів, до якої можна передати mycommand. Коли це станеться, останній xargsрозділить список і запустить іншу копію mycommand, і є ризик його залишити без завершення -f. Якщо ви хвилюєтесь у цій ситуації, ви можете замінити останнє xargs -0вище чимось таким:

... | xargs -x -0 mycommand

Це не вирішить проблему, але буде припинено роботу, mycommandколи список аргументів стає занадто довгим.


1
Ви ризикуєте перевищити ARG_MAXта виділити -fйого парний параметр.
Майкл Мол

@MichaelMol Це хороший момент, але я не думаю, що є якийсь змістовний спосіб вирішити цю ситуацію, не знаючи більше про це mycommand. Ви завжди можете додати -xостаннє xargs.
Satō Katsura

Я думаю, що правильне рішення, мабуть, зовсім не використовувати xargs, а просто використовувати, findякщо воно може бути використане. Цей розчин небезпечний; ви повинні хоча б попередити про випадок невдачі у своїй відповіді.
Майкл Мол

@MichaelMol Я справді не бачу, як findбуло б краще загальне рішення, особливо коли початкові аргументи - це не назви файлів. :)
Satō Katsura

Ми не знаємо, які початкові аргументи; ми бачимо лише наведений приклад, а не сценарій, який надихнув це питання. Інтуїція говорить про те, що з назвою аргументу -fта з прикладом інструменту, який lsвикористовується для ілюстрації, @ not-a-user має справу з іменами. І з огляду на findпропозиції -execаргумент, який дозволяє побудувати командний рядок, це добре. (Поки mycommandдозволено виконувати більше одного разу. Якщо це не так, то у нас є ще одна проблема з використанням xargsтут ...)
Michael Mol

5

Кращим способом вирішити його (IMO) було б:

  • в zsh:

    l=(a b c)
    mycommand -f$^l
    

    або використовуючи масив блискавки, щоб аргумент не був приєднаний до параметра:

    l=(a b c) o=(-f)
    mycommand "${o:^^l}"
    

    Таким чином, він все ще працює, якщо lмасив містить порожні елементи або елементи, що містять пробіли або будь-який інший проблемний символ для xargs. Приклад:

    $ l=(a '' '"' 'x y' c) o=(-f)
    $ printf '<%s>\n' "${o:^^l}"
    <-f>
    <a>
    <-f>
    <>
    <-f>
    <">
    <-f>
    <x y>
    <-f>
    <c>
    
  • в rc:

    l=(a b c)
    mycommand -f$l
    
  • в fish:

    set l a b c
    mycommand -f$l
    

(AFAIK, rcі fishне мають стиснути масив)

З подібними оболонками, подібними до Борна, як bashзавжди, ви завжди можете це зробити (все ж допускаючи будь-який символ в елементах $@масиву):

set -- a b c
for i do set -- "$@" -f "$i"; shift; done
mycommand "$@"

1
Ще один спосіб зробити це в bash - це названа змінна масиву. for i; do args+=('-f' "$i");done; mycommand "${args[@]}". IDK, якщо це швидше, але додавання 2-х елементів до масиву здається, що це має бути O (n), тоді як ваш setцикл, ймовірно, копіює та повторно аналізує накопичений список аргументів кожного разу (O (n ^ 2)).
Пітер Кордес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.