команда сборки путем конкатенации строки в bash

У меня есть сценарий bash, который строит командную строку в строке на основе некоторых параметров перед выполнением ее за один раз. Части, которые объединены в командную строку, должны быть разделены по трубам, чтобы облегчить «потоковое» передачу данных через каждый компонент.

Очень упрощенный пример:

#!/bin/bash
part1=gzip -c
part2=some_other_command
cmd="cat infile"

if [ ! "$part1" = "" ]
then
    cmd+=" | $part1"
fi


if [ ! "$part2" = "" ]
then
    cmd+=" | $part2"
fi


cmd+="> outfile"
#show command. It looks ok
echo $cmd
#run the command. fails with pipes
$cmd

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

Итак, мой вопрос заключается в том, можно ли построить команду таким образом , и что это лучший способ сделать это?

1
задан 4 June 2014 в 08:31

3 ответа

Одно из решений этого, для дальнейшего использования, - использовать «eval». Это гарантирует, что всякий раз, когда строка интерпретируется bash, забывается, и все это читается так, как если бы оно было напечатано непосредственно в оболочке (это именно то, что мы хотим).

Итак, в приведенном выше примере, заменив

$cmd

на

eval $cmd

.

4
ответ дан 24 May 2018 в 07:00
  • 1
    Будьте осторожны, хотя с указанными параметрами. eval foo "a b" будет таким же, как eval foo "a" "b". – udondan 25 August 2016 в 12:10

@waltinator уже объяснил, почему это не работает так, как вы ожидали. Другой способ - использовать bash -c для выполнения вашей команды:

$ comm="cat /etc/passwd"
$ comm+="| wc -l"
$ $comm
cat: invalid option -- 'l'
Try 'cat --help' for more information.
$ bash -c "$comm"
51
1
ответ дан 24 May 2018 в 07:00
  • 1
    Парсимония говорит мне не начинать другой процесс с bash -c, а использовать eval для выполнения команды в текущем процессе. – waltinator 4 June 2014 в 19:20
  • 2
    @waltinator уверен, я бы, вероятно, использовал eval для этого (вот почему я поддержал вас и Леннарта). Я просто предлагаю альтернативу. – terdon♦ 4 June 2014 в 19:24

Возможно, лучший способ сделать это - избегать использования eval и просто использовать массив Bash и его встроенное расширение для создания всех аргументов, а затем выполнить их по команде.

runcmd=() # This is slightly messier than declare -a but works
for cmd in $part1 $part2 $part3; do runcmd+="| $cmd "; done
cat infile ${runcmd[@]} # You might be able to do $basecmd ${runcmd[@]}
# but that sometimes requires an `eval` which isn't great
0
ответ дан 24 May 2018 в 07:00

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

Похожие вопросы: