子壳

子壳

我目前正在尝试制作一个脚本来创建字节,这些字节将通过管道作为 netcat 的输入。

这是脚本的想法:

(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port

我尝试使用子 shell 和命令替换(例如 $())来执行命令。但是我无法理解为什么使用命令替换时脚本的输出是错误的。我怀疑命令替换在执行多个命令时错误地输送其输出。有人可以向我解释为什么会这样吗?

编辑

这是使用命令替换的变体:

$(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port

答案1

好吧,让我们来分解一下。子 shell 执行链中的内容(即将它们分组)。这实际上具有直观意义,因为只需通过用 包围命令链即可创建子 shell ()。但是,除了在执行时将子 shell 的内容组合在一起之外,您仍然可以像使用单个命令一样使用子 shell。也就是说,子 shell 仍然有stdin,stdout因此stderr您可以通过管道将内容传入或传出子 shell。

另一方面,命令替换与简单地将命令链接在一起不同。相反,命令替换的作用有点像变量访问,但带有函数调用。与命令不同,变量没有标准文件描述符,因此您无法通过管道将任何内容传入或传出变量(一般来说),命令替换也是如此。

为了使这一点更清楚,下面是一组可能不清楚(但准确)的示例,以及一组我认为可能更容易理解的示例。

假设该date -u命令给出以下内容:

Thu Jul  2 13:42:27 UTC 2015

但是,我们想要操纵这个命令的输出。因此,让我们将其通过管道传输到类似的内容中sed

user@host~> date -u | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

哇,太有趣了!以下内容与上面完全等效(除了您可以在有关 shell 的手册页中阅读的一些环境差异之外):

user@host~> (date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

这应该不足为奇,因为我们所做的只是团体date -u。然而,如果我们执行以下操作,我们会得到一些一开始看起来有点奇怪的东西:

user@host~> $(date -u) | sed -e 's/ /    /g'
command not found: Thu

这是因为$(date -u)相当于准确地键入date -u输出内容。所以上面的内容等价于下面的内容:

user@host~> Thu Jul  2 13:42:27 UTC 2015 | sed -e 's/ /    /g'

当然,这会出错,因为Thu这不是一个命令(至少我不知道);它肯定不会通过管道传输任何内容stdout(因此sed永远不会得到任何输入)。

但是,由于我们知道命令替换就像变量一样,因此我们可以轻松解决这个问题,因为我们知道如何将变量的值通过管道传输到另一个命令中:

user@host~> echo $(date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

但,与 bash 中的任何变量一样,您可能应该用 引用命令替换""

现在,举一个也许更简单的例子;考虑以下:

user@host~> pwd
/home/hypothetical
user@host~> echo pwd
pwd
user@host~> echo "$(pwd)"
/home/hypothetical
user@host~> echo "$HOME"
/home/hypothetical
user@host~> echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
user@host~> (pwd)
/home/hypothetical

我不知道如何描述它比这更简单。命令替换的工作方式就像变量访问一样,其中子 shell 仍然像命令一样运行。

答案2

子壳

(command)command将在子 shell 中执行。如果您有多个命令,这一点很有用。

  • (ls) | wc将通过管道输出lsto wc,显然你可以写ls | wc.
  • (ls ; date) | wcls将把和的输出通过管道传输datewc。使用ls ; date | wc将导致仅通过date管道传输到wc.

代换

$(command)将执行command并替换为输出。例如

echo $(date)

将替换$(date)Thu Jul 2 15:20:43 CEST 2015,结果是

echo Thu Jul  2 15:20:43 CEST 2015

将两者放在一起

您可以将两者结合起来。

file=/hello/word
( printf "%s has %d bytes\n" "${file}" $(wc -c < "$file") ; date ) | netcat ...

在这里,您可以使用"$file""${file}"

不要忘记引用文件名,在幻想世界中文件名是纯文件,而在现实世界中文件名通常包含换行符、空格、逗号、制表符和括号。

相关内容