eval используется с командой piped

eval используется с командой piped

У меня есть файл file.txt с командой, сохраненной в одной строке (эта команда действительна при запуске в консоли), и я хочу выполнить ее в одной строке с помощью sh, например:

cat file.txt | eval

чего не хватает? есть какие-нибудь советы?

а что если у меня есть файл со многими командами (по одной на каждую строку) и я хочу выполнить только одну команду (одну целую строку)? Моя первая идея:

head -n5 | tail -n1 | eval

решение1

evalне считывает командную строку из stdin.

eval "$(cat file.txt)"
# or easier, in ksh/bash/zsh
eval "$(<file.txt)"
# usually you cannot be sure that a command ends at the end of line 5
eval "$(head -n 5 file.txt)"

Вместо evalможно использовать стандартный .или bash/ zsh/ ksh source, если команды в любом случае находятся в файле:

source ./file

(обратите внимание, что важно добавить, что ./. В противном случае sourceищет fileв , $PATHпрежде чем рассматривать fileв текущем каталоге. Если в режиме POSIX, bashдаже не будет рассматривать fileв текущем каталоге, даже если не найден в $PATH).

Конечно, это не работает с выбором части файла. Это можно сделать так:

head -n 5 file.txt >commands.tmp
source ./commands.tmp

Или (с ksh93, zsh, bash):

source <(head -n 5 file.txt)

решение2

Итак... решение вашего вопроса на 100% возможно и (в контексте make) важно.

Я столкнулся с этим при работе с make-файлом, и, учитывая сложность вложения команд bash в make-файл, который уже используется $(...)для вызова переменных, было бы неплохо иметь возможность сделать именно то, о чем вы спрашиваете.

Вместо использования evalпросто используйте системную команду awkили :perl

// command_list.sh:
echo "1"
echo "2"
echo "3"

// command line prompt:
$: cat command_list.sh | awk '{system($0)}'
1
2 
3

И, командное здание:

// a readable version--rather than building up an awk miniprogram, 
// split into logical blocks:

$: cat inputs.txt | awk '{print "building "$1" command "$2" here "}' | awk '{system($0)}' 

решение3

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

Однако, в зависимости от того, чего вы пытаетесь достичь, это может не иметь значения. В любом случае, вот запуск evalпротив содержимого трубы:

❯ echo echo hi | eval "$(cat -)"
hi

Вот пример подвоха. Что-то вроде следующего не будет напечатано 1:

❯ echo a=1 | eval "$(cat -)"; echo $a

Вместо этого нам придется сделать следующее:

❯ echo a=1 | { eval "$(cat -)"; echo $a; }
1

решение4

Если вы не полны решимости использовать eval, используйте sh:

cat file.txt | sh

Да, он будет работать в отдельном экземпляре sh, но этот факт документирован самостоятельно.

А также есть while read:

cat file.txt | while read cmd; do eval $cmd; done

Чтобы выполнить команду в 5-й строке файла file.txt:

sed -n 5p file.txt | sh

(Я понимаю, что это старый вопрос.)

Связанный контент