bash 在参数中转义冒号、等号、与号

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9932798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:54:49  来源:igfitidea点击:

Escape colons, equals, ampersands in arguments

bashcommand-lineescapingquotes

提问by

Below is my code, which behaves extremely bizarre, and I am not sure I understand the reason, but I think it's somehow connected to path expansion:

下面是我的代码,它的行为非常奇怪,我不确定我是否理解原因,但我认为它以某种方式与路径扩展有关:

EDIT:this is the asxgrabscript mentioned in the second listing:

编辑:这是asxgrab第二个清单中提到的脚本:

#!/usr/bin/env bash

let "i=0"

GET "" | grep 'href="mms://' | while read line
do
    echo "$line"
    address=`echo $line | grep -Eow '"[^"]+"'`
    address_length=$((${#address}-2))
    address=${address:1:address_length}
    echo "Grabbing '$address', attempt $i, $address_length"
    mplayer "'$address' -dumpstream -dumpfile '.wmv' -vf scale\=320\:240" > /dev/null
    if [ ! $? ]; then
        break 1
    fi
    let "i++"
done

I've tried dozens of different ways of escaping, quoting and whatnot, and I think I've exhausted my creativity... please help!

我已经尝试了几十种不同的转义、引用等方式,我想我已经耗尽了我的创造力......请帮忙!

Suppose the script is called with these arguments:

假设使用以下参数调用脚本:

./asxgrab 'http://switch3.castup.net/cunet/gm.asp?ai=16&ip=79.180.37.230&course=c20478/2012b&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&ar=c20478_12b_784_01_1&ticket=58353E7A69BF1B9XO655E9E683016C5255C08DD37211ECF495F72A64E5278AA434CSP3C10C028D604AAD6C39FE7D71386D230983BBAF58A2511D14222F95090AE2C4C55CB696B82919A5A8EB44EAF8954DEDB5' 'java.0'

The received response looks like this:

收到的响应如下所示:

<asx version="3.0">
    <!-- GMX -->
    <param name="encoding" value="utf-8" />
    <title>CastUP: c20478_12b_784_01_1</title>
    <MOREINFO HREF = "" />

    <entry>
    <PARAM NAME="EntryType" VALUE="Content" />

    <param name="encoding" value="utf-8" />
    <PARAM NAME="CastUP_AssociatedURL" VALUE="" />
    <PARAM NAME="CastUP_Content_Config" VALUE="" />
    <PARAM NAME="CastUP_Content_ClipMediaID" VALUE="9067325" />
    <author>openu</author>
        <title>CastUP: c20478_12b_784_01_1</title>
<ref href="mms://s3fwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=FE81687B-33CD-4441-A8F6-1DEC9923332C&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183" />
<ref href="...." />

    </entry>

When I do this:

当我这样做时:

mplayer "mms://s3fwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=C6527A33-587F-4148-A3D2-E7EDED51316B&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183" -dumpstream -dumpfile java0.wmv -vf scale=320:240

from the terminal, it works, but it doesn't work from the script. Instead it tries to trim the $lineor something like that. I don't even understand what happens, but the output is absolutely of no consequences...

从终端,它工作,但它不从脚本工作。相反,它试图修剪$line或类似的东西。我什至不明白会发生什么,但输出绝对没有任何后果......

This is my uni's site and this is, funny as it gets, a lecture on Java :)

这是我的大学网站,这是一个关于 Java 的讲座,虽然很有趣,但 :)

EDIT:

编辑:

<ref href="mms://s0dwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=111A3770-29DC-40EC-85EC-93453E2819D7&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183" />
Grabbing 'mms://s0dwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=111A3770-29DC-40EC-85EC-93453E2819D7&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183', attempt 0, 268
Can't open joystick device /dev/input/js0: No such file or directory
Can't init input joystick
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.
No stream found to handle url 'mms://s0dwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=111A3770-29DC-40EC-85EC-93453E2819D7&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183' -dumpstream -dumpfile 'java.0.wmv' -vf scale=320:240
d324d1043027b0720c295b93e4abb183" />
Grabbing '', attempt 1, -2
Can't open joystick device /dev/input/js0: No such file or directory
Can't init input joystick
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.
File not found: ''' -dumpstream -dumpfile 'java.0.wmv' -vf scale=320:240'
Failed to open '' -dumpstream -dumpfile 'java.0.wmv' -vf scale=320:240.
027b0720c295b93e4abb183" />

This is the output I'm getting from the script.

这是我从脚本中得到的输出。

MPlayer SVN-r31918 (C) 2000-2010 MPlayer Team
Can't open joystick device /dev/input/js0: No such file or directory
Can't init input joystick
mplayer: could not connect to socket
mplayer: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing mms://s3fwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=C6527A33-587F-4148-A3D2-E7EDED51316B&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183.
STREAM_ASF, URL: mms://s3fwm.castup.net/server12/16/798/79837168-61.wmv?ct=IL&rg=BZ&aid=16&ts=0&cu=C6527A33-587F-4148-A3D2-E7EDED51316B&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183
Resolving s3fwm.castup.net for AF_INET6...

Couldn't resolve name for AF_INET6: s3fwm.castup.net
Resolving s3fwm.castup.net for AF_INET...
Connecting to server s3fwm.castup.net[212.179.13.65]: 1755...

Connected
file object, packet length = 6100 (6100)
unknown object
unknown object
unknown object
stream object, stream ID: 1
stream object, stream ID: 2
unknown object
data object
mmst packet_length = 6100
Cache size set to 64 KBytes
Stream not seekable!

And this is the expected output.

这是预期的输出。

采纳答案by Adam Liss

Have you tried this?

你试过这个吗?

mplayer "$address" -dumpstream -dumpfile ".wmv" -vf "scale=320:240" > /dev/null

Secrets of bash:

bash的秘密:

  • Variables inside double-quotes are expanded; those inside single-quotes are not.
  • Words inside quotes are treated as a single token.
  • Quotes of one type escape those of the other type.
  • 双引号内的变量被扩展;里面的单引号不是。
  • 引号内的单词被视为单个标记。
  • 一种类型的引用会避开另一种类型的引用。

The original line

原来的线

mplayer "'$address' -dumpstream -dumpfile '.wmv' -vf scale\=320\:240" > /dev/null

called mplayerwith the single argument '$address' -dumpstream -dumpfile '$2.wmv' -vf scale\=320\:240, but mplayerwants each of those tokens to be a separate word.

所谓mplayer与所述单个参数'$address' -dumpstream -dumpfile '$2.wmv' -vf scale\=320\:240,但mplayer希望每个这些令牌的是一个单独的字。

回答by ruakh

If I'm understanding everything correctly, the only real problem I see is that this line:

如果我正确理解一切,我看到的唯一真正的问题是这一行:

    mplayer "'$address' -dumpstream -dumpfile '.wmv' -vf scale\=320\:240" > /dev/null

is supposed to be this:

应该是这样的:

    mplayer "$address" -dumpstream -dumpfile ".wmv" -vf scale=320:240 > /dev/null

That is, you need to remove the double-quotes that gather all of mplayer's arguments into a single argument, and you need to remove the single-quotes around, and backslashes inside, some of those arguments.

也就是说,您需要删除将 的所有mplayer参数收集到单个参数中的双引号,并且您需要删除其中一些参数周围的单引号和反斜杠。

Other things I might change for cleanliness' sake:

为了清洁我可能会改变的其他事情:

  • changing read lineto read -r linewould eliminate any potential weirdness from backslashes.
  • a line line="${line%$'\r'}"at the beginning of the while-loop body would lay to rest any concern about stray carriage-returns.
  • changing address=`echo $line ...to address=`echo "$line" ...would eliminate any risk of word-splitting and filename-expansion and whatnot (not that they seem very likely as it is).
  • the [ ! $? ]test is meaningless (since $?is never blank, is it?); changing it to just && break 1at the end of the previous command would be clearer IMHO, and more effective.
  • 更改read lineread -r line将消除反斜杠中任何潜在的怪异现象。
  • -loop 正文line="${line%$'\r'}"开头的一行while可以消除对杂散回车的任何担忧。
  • 更改address=`echo $line ...address=`echo "$line" ...将消除分词和文件名扩展等的任何风险(并不是因为它们看起来很有可能)。
  • [ ! $? ]测试是没有意义的(因为$?是从来没有空,是吗?); && break 1恕我直言,将其更改为仅在上一个命令的末尾会更清晰,也更有效。

回答by karatedog

You bash script is very "imperative" as it has been rewritten from Assembly.

您的 bash 脚本非常“重要”,因为它是从 Assembly 中重写的。

Another approach:

另一种方法:

  • get the descriptor file
  • clean the descriptor file (leave mms://... strings in it)
  • use that cleaned result as input for cyclic processing
  • 获取描述符文件
  • 清理描述符文件(在其中留下 mms://... 字符串)
  • 使用清洗后的结果作为循环处理的输入

This was a one liner, I just break it up. You'd put the code between the do..done. I didn't care about the file names being ginormous, I gave them as the output .wmv:

这是一个单衬,我只是把它拆开。你会把代码放在 do..done 之间。我不在乎文件名太大,我把它们作为输出.wmv:

link="http://switch3.castup.net/cunet/gm.asp?ai=16&ip=79.180.37.230&course=c20478/2012b&cuud=user:77f6c69526b9fa05f78d3d6679630308d324d1043027b0720c295b93e4abb183&ar=c20478_12b_784_01_1&ticket=58353E7A69BF1B9XO655E9E683016C5255C08DD37211ECF495F72A64E5278AA434CSP3C10C028D604AAD6C39FE7D71386D230983BBAF58A2511D14222F95090AE2C4C55CB696B82919A5A8EB44EAF8954DEDB5"

for i in $(curl -s "$link" | awk '/mms/ {gsub (/<ref href="/, ""); gsub(/" \/>/, ""); print ##代码##}')
do
  mplayer $i -dumpstream -dumpfile $i.wmv -vf scale=320:240
done