Running a command that is stored in a variable (including pipes and redirects)

北战南征 提交于 2019-12-24 11:42:06

问题


I'm writing a script that functions as a "talking terminal" (you type in commands and it says the output) and so far my code is:

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
espeak "$($COMMAND)"
done

and it works for simple commands:

bash$ ./talkingterminal.sh
~> ls
# espeak says "talkingterminal.sh"

but when I use pipes etc:

bash$ ./talkingterminal.sh
~>ip addr | grep inet
Command "|" is unknown, try "ip addr help".
~>

and that command works in bash and gives the expected output. any help? thanks, Martin


回答1:


This is a rare case where eval is appropriate; you just putting a thin wrapper around what is already unlimited access to the command line. More importantly, you aren't modifying COMMAND in any unexpected ways. What the user types is what will be executed.

#!/bin/bash
while : ; do
    IFS= read -rp "~> " COMMAND
    espeak "$(eval "$COMMAND")"
done

A few notes:

  1. The read builtin in bash can display a custom prompt using the -p option.
  2. Use the : or true commands, which always succeed, to set up an infinite loop.
  3. Use the -r option and an empty value for IFS to ensure that COMMAND is set to the exact line typed by the user.
  4. Quote $COMMAND so that the entire string is passed to eval without any previous shell parsing.
  5. Note that this still cannot handle multi-line input in the same fashion as the shell itself. (For example, a line like for x in 1 2 3; do will not prompt you for the body of the loop.)



回答2:


A simple solution is to use eval:

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
espeak "$(eval $COMMAND)"
done

Then you can print output to the shell as well easily:

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
OUTPUT="$(eval $COMMAND)"
echo $OUTPUT
espeak "$($OUTPUT)"
done



回答3:


Have you tried to use the "-r" option? This option avoids interpreting special characters. Additionally you have to remove the external $() in the line:

espeak "$($COMMAND)"

It should be:

espeak "$(COMMAND)"


来源:https://stackoverflow.com/questions/32824972/running-a-command-that-is-stored-in-a-variable-including-pipes-and-redirects

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!