#bash #dialog
#bash
Вопрос:
У меня есть скрипт на Perl, который выдает мне определенный список случайных чисел, соответствующих строкам файла. Затем я хочу извлечь эти строки из файла, используя sed
.
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var=$(perl test.pl test2 $count)
Переменная var
возвращает вывод, подобный: cat last_queries.txt | sed -n '12p;500p;700p'
. Проблема в том, что я не могу выполнить эту последнюю команду. Я пробовал $var
, но вывод неверен (если я запускаю команду вручную, она работает нормально, так что проблем нет). Каков правильный способ сделать это?
P.S: Конечно, я мог бы выполнить всю работу на Perl, но я пытаюсь научиться этому, потому что это может помочь мне в других ситуациях.
Ответ №1:
Вам просто нужно сделать:
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
$(perl test.pl test2 $count)
Однако, если вы хотите вызвать свою команду Perl позже, и именно поэтому вы хотите присвоить ее переменной, то:
#!/bin/bash
count=$(cat last_queries.txt | wc -l)
var="perl test.pl test2 $count" # You need double quotes to get your $count value substituted.
...stuff...
eval $var
Согласно справке Bash:
~$ help eval
eval: eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
Комментарии:
1. Без
eval
этого не будет работать должным образом. Попробуйтеvar='printf "%sn" "first item" "second item" "third item"
и сравните$var
сeval "$var"
. Первое просто неверно по причинам, описанным в BashFAQ # 50 .2. … то есть:
$(perl test.pl test2 $count)
должно бытьeval "$(perl test.pl test2 $count)"
, чтобы избежать ошибок, которые документирует BashFAQ # 50.3. Это работает (у меня также были проблемы с командной строкой, содержащей »
|
«, как в вопросе). Если необходимо получить вывод (для стандартного вывода) , то это можно сделать с помощьюsomeoutput=$(eval $var)
, а не простоeval $var
. Возможно, немного расширить ответ?
Ответ №2:
Вы, вероятно, ищете eval $var
.
Комментарии:
1. Это сработало при
$($cmd))
сбое. Он всегда говорит, что команда не найдена. Спасибо!
Ответ №3:
Существует 2 основных способа выполнения строковой команды в сценарии оболочки, независимо от того, задана она как параметр или нет.
COMMAND="ls -lah"
$(echo $COMMAND)
или
COMMAND="ls -lah"
bash -c $COMMAND
Комментарии:
1. Спасибо, это немного помогло. Но у вас есть идея, почему
bash -c "cd /home/user/dev/"
это не работает?2. @andylib93
cd
влияет только на текущий процесс, если вы запуститеbash -c "cd /home/user/dev/"
, он запустит новыйbash
процесс и запуститсяcd
в рамках этого процесса. Дочерний процесс отлично изменит каталог, но это не повлияет на оболочку, в которой вы запустилиbash
команду.
Ответ №4:
line=$((${RANDOM} % $(wc -l < /etc/passwd)))
sed -n "${line}p" /etc/passwd
вместо этого просто с вашим файлом.
В этом примере я использовал файл /etc/password, используя специальную переменную ${RANDOM}
(о которой я узнал здесь ), и sed
выражение, которое у вас было, разница только в том, что я использую двойные кавычки вместо одинарных, чтобы разрешить расширение переменной.
Ответ №5:
В случае, когда у вас есть несколько переменных, содержащих аргументы для команды, которую вы запускаете, а не только одну строку, вы не должны использовать eval напрямую, так как это приведет к сбою в следующем случае:
function echo_arguments() {
echo "Argument 1: $1"
echo "Argument 2: $2"
echo "Argument 3: $3"
echo "Argument 4: $4"
}
# Note we are passing 3 arguments to `echo_arguments`, not 4
eval echo_arguments arg1 arg2 "Some arg"
Результат:
Argument 1: arg1
Argument 2: arg2
Argument 3: Some
Argument 4: arg
Обратите внимание, что, хотя «Некоторый аргумент» был передан как один аргумент, eval
считайте его как два.
Вместо этого вы можете просто использовать строку в качестве самой команды:
# The regular bash eval works by jamming all its arguments into a string then
# evaluating the string. This function treats its arguments as individual
# arguments to be passed to the command being run.
function eval_command() {
"$@";
}
Обратите внимание на разницу между выводом eval
и новой eval_command
функцией:
eval_command echo_arguments arg1 arg2 "Some arg"
Результат:
Argument 1: arg1
Argument 2: arg2
Argument 3: Some arg
Argument 4:
Комментарии:
1. Чтобы избежать вычисления каждого элемента после пробела, как в вашем первом примере с eval, заключите его в одинарные кавычки :
eval 'echo_arguments arg1 arg2 "Some arg"'
. Тогда результат будет таким, как во втором примере.
Ответ №6:
Лучшие способы сделать это
Использование функции:
# define it
myls() {
ls -l "/tmp/test/my dir"
}
# run it
myls
Использование массива:
# define the array
mycmd=(ls -l "/tmp/test/my dir")
# run the command
"${mycmd[@]}"
Ответ №7:
cmd="ls -atr ${HOME} | tail -1" <br/>
echo "$cmd" <br/>
VAR_FIRST_FILE=$( eval "${cmd}" ) <br/>
или
cmd=("ls -atr ${HOME} | tail -1") <br/>
echo "$cmd" <br/>
VAR_FIRST_FILE=$( eval "${cmd[@]}" )