как передать «один» аргумент и использовать его дважды в команде «xargs»

#bash #shell #echo #popen #xargs

#bash #оболочка #echo #popen #xargs

Вопрос:

Я пытался использовать xargs для передачи аргументов в echo :

 [usr@linux scripts]$ echo {0..4} | xargs -n 1 echo
0
1
2
3
4
  

-n 1 гарантировал, что xargs аргументы будут 1 передаваться echo раз за разом в

Затем я хочу использовать этот аргумент дважды, однако результаты не те, которые я хотел:

 [usr@linux scripts]$ echo {0..4} | xargs -I@ -n 1 echo @,@
0 1 2 3 4,0 1 2 3 4
  

-n 1 кажется отключенным, когда я добавил -I@ ,
и это тот результат, который я хотел:

 0,0
1,1
2,2
3,3
4,4
  

как я могу этого добиться?

———Поставка—————— Я использовал метод, рекомендованный @123 , однако есть еще один вопрос:

test.sh:

 #!/bin/bash
a[0]=1
a[1]=2
echo "a[0] and a[1] : "${a[0]}, ${a[1]}
echo -n {0..1} | xargs -I num -d" " echo num,${a[num]},num
  

и это результат:

 [usr@linux scripts]$ sh test.sh 
a[0] and a[1] : 1, 2
0,1,0
1,1,1
  

вы можете видеть, что массив a возвращает не то значение, которое я хотел :<
И как я могу решить эту проблему?

Комментарии:

1. echo -n {0..4} | xargs -I@ -d' ' echo @,@ ? printf "%sn" {0..4} | xargs -I@ echo @,@ ?

2. не могли бы вы взглянуть на этот вопрос, который я только что обновил? При использовании аргументов все еще возникают некоторые вопросы: (@123

3. Расширение оболочки происходит до того, как xargs его увидит, поэтому оно всегда оценивается как ${a[num]} aka ${a[0]} . можно было бы сделать что-то глупое вроде xargs -I num -d" " bash -c 'echo $num' "${a[@]}" но, вероятно, есть лучший способ достичь любой вашей конечной цели.

4. @123 У меня просто есть некоторые сомнения по поводу bash -c 'echo $num' "${a[@]}" того, как насчет первых echo $num работ? Похоже, что $num заменяется @ в ${a[@]} ?

5. И я только что попробовал подобную команду a[0]=x;a[1]=y;num=1;bash -c 'echo $num' "{a[@]}" , результат, который я ожидал, равен y, однако результат просто пустой.

Ответ №1:

Если вы не можете изменить формат ввода, вы могли бы установить разделитель на пробел:

 $ echo -n {0..4} | xargs -d " " -I@ echo @,@
0,0
1,1
2,2
3,3
4,4
  

В противном случае измените входные данные, чтобы разделить токены новой строкой:

 $ printf "%sn" {0..4} | xargs -I@ echo @,@
0,0
1,1
2,2
3,3
4,4
  

Причина такого синтаксиса объясняется в man xargs

 -I replace-str

Replace occurrences of replace-str in the  initial-arguments  with  names  read  from
standard input.  Also, unquoted blanks do not terminate input items; instead the sep‐
arator is the newline character.  Implies -x and -L 1.
  

Поэтому вы должны вручную установить разделитель на пробел, если хотите разграничить поля.

Комментарии:

1. @123: Я не совсем уверен, почему версия OP не работает. По-видимому, xargs разбивает строку ввода на пробелы, когда -I опция не используется, но с -I она обрабатывает строку как один аргумент. Я не смог найти хорошего объяснения этого на странице руководства…

2. Под -I > Also, unquoted blanks do not terminate input items; instead the separator is the newline character.

3. Не могли бы вы взглянуть на вопрос, который я только что обновил? Все еще есть некоторые вопросы в использовании аргументов:(

4. @springcc: повторите редактирование, причина, по которой это не работает, заключается в том, что переменные заменяются перед выполнением xargs, поэтому ${a[num]} получает первое значение массива, поскольку var оно не определено. Вы могли бы решить это с помощью eval, но, вероятно, есть лучшее решение…

5. @springcc Вы столкнулись с давно известной проблемой. Вы не можете использовать xagrs -I замену в качестве итератора массива. Итак, вам нужно вызвать некоторую подоболочку через eval или просто с помощью bash -c . Итак, вам нужно будет экспортировать свой массив, но… Вы не можете экспортировать массив в bash 🙂 Из manpage: Array variables may not (yet) be exported. На самом деле, для этого есть несколько способов, но лучший способ — настроить логику вашего скрипта и предоставить xargs только обычные переменные.