传递给命令行参数时如何在Bash中转义变量 [英] How to escape a variable in Bash when passing to a command-line argument

查看:187
本文介绍了传递给命令行参数时如何在Bash中转义变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Bash脚本(Cygwin),该脚本使用一些Windows路径,其中包含空格.因此,我在变量定义中使用了\转义了空格.

I've got a Bash script (Cygwin) that uses some Windows paths with spaces in them. Consequently, I have escaped the space with a \ in my variable definition.

脚本中的所有内容都可以正常工作.但是,我需要将此变量作为参数传递给命令行可执行文件.当我这样做时,我的逃脱变得一团糟.

Everything within the script works fine. However, I need to pass this variable as an argument to a command-line executable. When I do that, my escaping gets messed up.

示例非功能脚本:

#!/bin/sh

# File paths
destinationPath="/cygdrive/c/Documents and Settings/Eric/My Documents/"
attachments="\n2013-12-12.pdf"
body="Test Body"
recipient="asdf@asdf.com"


# Prepare attachments
args=""
for file in $attachments ; do
    file=${file//[ \\n]/}
    touch $file
    mv $file "$destinationPath/$file"
    args="$args -a $destinationPath/$file"
done


# Send email
echo -e $body | email --from-addr nosender@mydomain.com --from-name "Automated CSS Downloader" --subject "Downloaded new file(s) \
  from CSS" $args eric@mydomain.com

脚本输出:

$ bash -x test.sh
+ destinationPath='/cygdrive/c/Documents and Settings/Eric/My Documents/'
+ attachments='\n2013-12-12.pdf'
+ body='Test Body'
+ recipient=asdf@asdf.com
+ args=
+ for file in '$attachments'
+ file=2013-12-12.pdf
+ touch 2013-12-12.pdf
+ mv 2013-12-12.pdf '/cygdrive/c/Documents and Settings/Eric/My Documents//2013-12-12.pdf'
mv: listing attributes of `2013-12-12.pdf': Invalid argument
+ args=' -a /cygdrive/c/Documents and Settings/Eric/My Documents//2013-12-12.pdf'
+ echo -e Test Body
+ email --from-addr nosender@mydomain.com --from-name 'Automated CSS Downloader' --subject 'Downloaded new file(s) from CSS' -a /cygdrive/c/Documents and Settings/Eric/My Documents//2013-12-12.pdf eric@mydomain.com
email: WARNING: Email address 'and' is invalid. Skipping...
email: FATAL: Could not open attachment: /cygdrive/c/Documents: No such file or directory

因此,如您所见,路径中的转义空间未在$ args变量中导出.我假设错误出现在"args = ..."行上.但是我不确定如何对$ destinationPath进行转义以确保保留转义的字符.

So, as you can see, the escaped space in the path is not being exported in the $args variable. I am assuming the error comes on the line "args=...". But I am not sure how to escape $destinationPath to ensure that the escaped characters are retained.

我尝试在destinationPath中使用双引号(无转义空格),但无济于事.如果我尝试在args =行中双引号$ destinationPath,那么输出也将被一堆额外的引号搞乱.

I've tried using double quotes (with no escaped space) in destinationPath, but to no avail. If I try to double quote $destinationPath in the args= line, then the output also gets all screwed up with a bunch of extra quoting.

我该如何使用它?我试过使用$ IFS变量,但是我真的不知道我在用它做什么,而且似乎也无法使其工作,尽管我怀疑解决方案与$有关. IFS.

How can I get this to work? I've tried playing around with the $IFS variable, but I don't really know what I'm doing with it and can't seem to get it working with that either, although I suspect the solution has something to do with $IFS.

推荐答案

没有数组就没有很好的方法. (使用eval并不是一种好方法,但是数组更简单.)

There's no good way of doing this without an array. (There's a not good way of doing it, using eval, but the array is simpler.)

问题在于,您希望每个文件最终都作为email的一个参数,但是您希望将所有这些参数累加到Bash变量中.根本没有办法做到:您可以将Bash变量作为单个参数("$arg")插入,也可以将其插入,因为无论它分成多少单词($arg),但是您无法根据创建变量时是否转义空格来对它进行拆分,因为Bash仅记住分配给变量的字符串,而不记住转义标记.

The problem is that you want each file to end up as one argument to email, but you want to accumulate all those arguments into a Bash variable. There's just no way to do that: you can cause the Bash variable to be inserted as a single argument ("$arg") or you can cause it to be inserted as however many words it gets split into ($arg), but you can't get it to be split according to whether or not spaces were escaped when the variable was created, because Bash only remembers the string assigned to a variable, not the escape marks.

但是,您可以使用数组,因为您可以使每个文件名恰好是一个数组元素,并且可以让Bash将数组作为每个元素的一个参数插入.

However, you can do it with an array, because you can make every filename exactly one array element, and you can get Bash to insert an array as one argument per element.

方法如下:

# File paths                                                                                                                              
destinationPath="/cygdrive/c/Documents and Settings/Eric/My Documents/"
attachments="\n2013-12-12.pdf"
body="Test Body"
recipient="asdf@asdf.com"


# Prepare attachments                                                                                                             
args=()
for file in $attachments ; do
    file=${file//[ \\n]/}
    touch $file
    mv $file "$destinationPath/$file"
    args+=(-a "$destinationPath/$file")
done

# Send email                                                                                                                      
echo -e $body |
  email --from-addr nosender@mydomain.com \
        --from-name "Automated CSS Downloader" \
        --subject "Downloaded new file(s) from CSS" \
        "${args[@]}" eric@mydomain.com

您可能还想将attachments变量放入一个数组中.从出现换行符开始,我假设您实际上是在以某种更复杂的方式进行设置,所以我没有更改代码.但是,如果附件名称中有空格,则您当前的代码将无法工作(而且我很确定,换行符将通过for形式的参数扩展来消除,除非您更改了$IFS,因此不必file=${file//[ \\n]/}.)

You might also want to make the attachments variable into an array; from the presence of the newline character, I'm assuming that you're actually setting it in some more complicated way, so I didn't change the code. But your current code won't work if the attachment name has a space in it (and I'm pretty sure that the newline will be eliminated by the parameter expansion in the for form, unless you've altered the value of $IFS, so file=${file//[ \\n]/} shouldn't be necessary.)

这篇关于传递给命令行参数时如何在Bash中转义变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆