Порядок оценки выражений Bash в командной строке - PullRequest
1 голос
/ 03 февраля 2012

Справочная информация:

Я работаю над быстрым вызовом выражений командной строки bash внутри программы отправки заданий SGE qSub параллельно.При этом я пытался передать выражение (в качестве аргумента) для запуска внутри другого скрипта, например:

. / RunArguments.sh grep foo bar.txt> output.txt

runArguments.sh выглядит так:

#!/bin/bash  
${1} ${2} ${3} etc....to 12

Идея состоит в том, что я хочу вывод grep foo bar.txt>.txt "для оценки в сценарии ... НЕ НА КОМАНДНОЙ СТРОКЕ.В приведенном выше примере «grep foo bar.txt» будет оцениваться во время выполнения runArguments.sh, но перенаправление вывода будет оцениваться в командной строке.В конце концов я нашел рабочее решение с использованием «eval», которое показано ниже, но я не понимаю, почему это работает.

Вопрос (ы)

1) Почему

./runArguments.sh eval "grep foo bar.txt > output.txt"

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

./runArguments.sh $(grep foo bar.txt > output.txt)

вычисляется в командной строке до вызова сценария?(вместо аргументов принимается вывод $ (grep ...))

2) Есть ли лучший способ сделать это?

Заранее спасибо!

1 Ответ

3 голосов
/ 03 февраля 2012

На ваш первый вопрос довольно сложно ответить, потому что вы уже ответили на него сами.Как вы видели, подстановка команды (запись $(...) или `...`) заменяет вывод команды, а затем обрабатывает результат.Например, это:

cat $(echo tmp.sh)

преобразуется в это:

cat tmp.sh

Так что в вашем случае это:

./runArguments.sh $(grep foo bar.txt > output.txt)

работает grep foo bar.txt > output.txt, захватываетего вывод - который будет ничем, поскольку вы перенаправили любой вывод в output.txt - и подставили его, получив:

./runArguments.sh

(поэтому ваш скрипт запускается без аргументов).

Напротив, это:

./runArguments.sh eval "grep foo bar.txt > output.txt"

не выполняет подстановку команд, поэтому ваш скрипт запускается с двумя аргументами: eval и grep foo bar.txt > output.txt.Эта команда внутри вашего скрипта:

${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

, следовательно, эквивалентна этой:

eval grep foo bar.txt '>' output.txt

, которая вызывает встроенный eval с пятью аргументами: grep, foobar.txt, > и output.txt.Встроенный eval собирает свои аргументы в команду, запускает их и даже переводит аргументы > и output.txt в перенаправление вывода, поэтому приведенное выше эквивалентно следующему:

grep foo bar.txt > output.txt

.,,и вы уже знаете, что это делает.: -)


Что касается вашего второго вопроса - нет, на самом деле нет лучшего способа сделать это.Вам нужно передать > в качестве аргумента, и это означает, что вам нужно использовать eval ... или bash -c "..." или подобное, чтобы «перевести» его обратно в значение перенаправления вывода.Если вы согласны с изменением сценария, вы можете изменить эту строку:

${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

на эту:

eval ${1} ${2} ${3} ${4} ${5} ${6} ${7} ${8} ${9} ${10} ${11} ${12}

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

eval ${@}

, что позволит вам передать более двенадцати параметров;или, что еще лучше, это:

eval "${@}"

, который даст вам немного больший контроль над разделением слов, захватом файлов и прочее.

...