重定向的奇怪语法
Strange syntax for a redirection
我刚刚在浏览 this 问题时遇到了以下脚本:
rm -f out
mkfifo out
trap "rm -f out" EXIT
while true
do
cat out | nc -l 1500 > >( # parse the netcat output, to build the answer redirected to the pipe "out".
export REQUEST=
while read line
do
line=$(echo "$line" | tr -d '[\r\n]')
if echo "$line" | grep -qE '^GET /' # if line starts with "GET /"
then
REQUEST=$(echo "$line" | cut -d ' ' -f2) # extract the request
elif [ "x$line" = x ] # empty line / end of request
then
HTTP_200="HTTP/1.1 200 OK"
HTTP_LOCATION="Location:"
HTTP_404="HTTP/1.1 404 Not Found"
# call a script here
# Note: REQUEST is exported, so the script can parse it (to answer 200/403/404 status code + content)
if echo $REQUEST | grep -qE '^/echo/'
then
printf "%s\n%s %s\n\n%s\n" "$HTTP_200" "$HTTP_LOCATION" $REQUEST ${REQUEST#"/echo/"} > out
elif echo $REQUEST | grep -qE '^/date'
then
date > out
elif echo $REQUEST | grep -qE '^/stats'
then
vmstat -S M > out
elif echo $REQUEST | grep -qE '^/net'
then
ifconfig > out
else
printf "%s\n%s %s\n\n%s\n" "$HTTP_404" "$HTTP_LOCATION" $REQUEST "Resource $REQUEST NOT FOUND!" > out
fi
fi
done
)
done
然而,我仍在努力 "decode" 第 6 行中的语法,即:> >
一方面,我希望 >
个字符之间没有任何空白 space - 一旦我删除那个空白 space 脚本就不会 运行 了。
另一方面,我不希望找到发送到另一个进程的重定向,因为在这些情况下,简单的管道将是完美的选择。实际上,我用 |
和脚本 运行 顺利地替换了 > >
。
长话短说,你能给我解释一下吗:
- 为什么中间的空格 space 是强制性的?
- > > 命令的语义是什么? (我猜是重定向!)
- 为什么不使用管道而不是重定向?
提前谢谢你。
语法不是> >
,而是> >()
。那是 process substitution。基本上 bash 创建一个命名管道,在管道内部的进程上使用标准输入作为有效文件提供给外部进程。
任何重定向到管道的内容都将被管道内的进程读取为标准输入。在您的情况下,该过程本身就是一个多行 bash 脚本。
如果您将 > >
替换为管道,您的脚本将大致相同,但您有点作弊。同样,实际的语法不是 > >
,而是 > >()
,因此当您将其更改为 | ()
时,您实际上是在传递到一个显式子 shell(括号内的部分)。没有那个子外壳你有
cat out | nc -l 1500 | export REQUEST=
...
export
不读取标准输入,脚本的其余部分不会成为管道的一部分,因此它的行为不会一致。
我刚刚在浏览 this 问题时遇到了以下脚本:
rm -f out
mkfifo out
trap "rm -f out" EXIT
while true
do
cat out | nc -l 1500 > >( # parse the netcat output, to build the answer redirected to the pipe "out".
export REQUEST=
while read line
do
line=$(echo "$line" | tr -d '[\r\n]')
if echo "$line" | grep -qE '^GET /' # if line starts with "GET /"
then
REQUEST=$(echo "$line" | cut -d ' ' -f2) # extract the request
elif [ "x$line" = x ] # empty line / end of request
then
HTTP_200="HTTP/1.1 200 OK"
HTTP_LOCATION="Location:"
HTTP_404="HTTP/1.1 404 Not Found"
# call a script here
# Note: REQUEST is exported, so the script can parse it (to answer 200/403/404 status code + content)
if echo $REQUEST | grep -qE '^/echo/'
then
printf "%s\n%s %s\n\n%s\n" "$HTTP_200" "$HTTP_LOCATION" $REQUEST ${REQUEST#"/echo/"} > out
elif echo $REQUEST | grep -qE '^/date'
then
date > out
elif echo $REQUEST | grep -qE '^/stats'
then
vmstat -S M > out
elif echo $REQUEST | grep -qE '^/net'
then
ifconfig > out
else
printf "%s\n%s %s\n\n%s\n" "$HTTP_404" "$HTTP_LOCATION" $REQUEST "Resource $REQUEST NOT FOUND!" > out
fi
fi
done
)
done
然而,我仍在努力 "decode" 第 6 行中的语法,即:> >
一方面,我希望 >
个字符之间没有任何空白 space - 一旦我删除那个空白 space 脚本就不会 运行 了。
另一方面,我不希望找到发送到另一个进程的重定向,因为在这些情况下,简单的管道将是完美的选择。实际上,我用 |
和脚本 运行 顺利地替换了 > >
。
长话短说,你能给我解释一下吗:
- 为什么中间的空格 space 是强制性的?
- > > 命令的语义是什么? (我猜是重定向!)
- 为什么不使用管道而不是重定向?
提前谢谢你。
语法不是> >
,而是> >()
。那是 process substitution。基本上 bash 创建一个命名管道,在管道内部的进程上使用标准输入作为有效文件提供给外部进程。
任何重定向到管道的内容都将被管道内的进程读取为标准输入。在您的情况下,该过程本身就是一个多行 bash 脚本。
如果您将 > >
替换为管道,您的脚本将大致相同,但您有点作弊。同样,实际的语法不是 > >
,而是 > >()
,因此当您将其更改为 | ()
时,您实际上是在传递到一个显式子 shell(括号内的部分)。没有那个子外壳你有
cat out | nc -l 1500 | export REQUEST=
...
export
不读取标准输入,脚本的其余部分不会成为管道的一部分,因此它的行为不会一致。