如何在传递到命令行参数时转义Bash中的变量

如何在传递到命令行参数时转义Bash中的变量,bash,variables,escaping,ifs,Bash,Variables,Escaping,Ifs,我有一个Bash脚本(Cygwin),它使用一些带有空格的Windows路径。因此,我用变量定义中的\来转义空间 脚本中的所有内容都很好。但是,我需要将此变量作为参数传递给命令行可执行文件。当我这么做的时候,我的逃跑就搞砸了 示例非功能脚本: #!/bin/sh # File paths destinationPath="/cygdrive/c/Documents and Settings/Eric/My Documents/" attachments="\n2013-12-12.pdf" b

我有一个Bash脚本(Cygwin),它使用一些带有空格的Windows路径。因此,我用变量定义中的
\
来转义空间

脚本中的所有内容都很好。但是,我需要将此变量作为参数传递给命令行可执行文件。当我这么做的时候,我的逃跑就搞砸了

示例非功能脚本:

#!/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以确保转义字符被保留

我尝试在destinationPath中使用双引号(没有转义空格),但没有效果。如果我尝试在args=行中双引号$destinationPath,那么输出也会因为一堆额外的引号而变得一团糟


我怎样才能让它工作?我尝试过使用$IFS变量,但我真的不知道我在用它做什么,似乎也无法让它使用它,尽管我怀疑解决方案与$IFS有关。

在字符串中提供destinationPath时,需要转义双引号

这应该起作用:

#!/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"
            #HERE YOU NEED ESCAPED DOUBLEQUOTED
            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

在字符串中提供destinationPath时,需要转义双引号

这应该起作用:

#!/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"
            #HERE YOU NEED ESCAPED DOUBLEQUOTED
            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

如果没有数组,就没有很好的实现方法。(使用
eval
不是一种很好的方法,但是数组更简单。)

问题在于,您希望每个文件都作为
电子邮件
的一个参数结束,但希望将所有这些参数累积到一个Bash变量中。没有办法做到这一点:可以将Bash变量作为单个参数插入(
“$arg”
),也可以将其插入为拆分成多少个字(
$arg
),但无法根据创建变量时是否转义空格来拆分,因为Bash只记住分配给变量的字符串,而不记得转义标记

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

以下是方法:

# 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

您可能还希望将
附件
变量设置为一个数组;从新行字符的出现,我假设您实际上是以更复杂的方式设置它,所以我没有更改代码。但是,如果附件名称中有空格,则当前代码将不起作用(我非常确定,换行符将被
for
表单中的参数扩展消除,除非您更改了
$IFS
的值,因此
file=${file/[\\n]/}
应该没有必要)如果没有阵列,就没有好的方法可以做到这一点。(使用
eval
不是一种很好的方法,但是数组更简单。)

问题在于,您希望每个文件都作为
电子邮件
的一个参数结束,但希望将所有这些参数累积到一个Bash变量中。没有办法做到这一点:可以将Bash变量作为单个参数插入(
“$arg”
),也可以将其插入为拆分成多少个字(
$arg
),但无法根据创建变量时是否转义空格来拆分,因为Bash只记住分配给变量的字符串,而不记得转义标记

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

以下是方法:

# 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

您可能还希望将
附件
变量设置为一个数组;从新行字符的出现,我假设您实际上是以更复杂的方式设置它,所以我没有更改代码。但是,如果附件名称中有空格,则当前代码将不起作用(我非常确定,换行符将被
for
表单中的参数扩展消除,除非您更改了
$IFS
的值,因此
file=${file/[\\n]/}
应该没有必要)

您是否尝试过双重逃离空间?例如,
Documents\\\和\\\
我尝试过,但遇到了两个问题:1)我的mv无法工作,因为它正在尝试将文件移动到Documents\\和\\(即:bash吞下了一个转义),电子邮件表达式中$args的扩展将变成:-a'/cygdrive/c/Documents\''和\''Settings/Eric/My\'Documents/a.J/CSS//2013-06-21.pdf。这不适用于每个空间的“多个”的b/c。也许您可以将destinationPath引入双引号并删除转义空间?其余的和你一样我已经尝试了我能想到的几乎所有组合。如果我使用双引号的desinationPath(没有转义字符串),电子邮件扩展将在没有引号的情况下出现,然后再次中断。我已经用一个功能齐全的示例脚本编辑了我的原始问题。胡乱猜测,但请尝试将
$destinationPath/$file
替换为
\“$destinationPath/$file\”
,看看它是否有助于您尝试双重转义空格?例如,
Documents\\\和\\\
我尝试过,但遇到了两个问题:1)我的mv无法工作,因为它正在尝试将文件移动到Documents\\和\\(即:bash吞下了一个转义),电子邮件表达式中$args的扩展将变成:-a'/cygdrive/c/Documents\''和\''Settings/Eric/My\'Documents/a.J/CSS//2013-06-21.pdf。这不适用于每个空间的“多个”的b/c。也许您可以将destinationPath引入双引号并删除转义空间?其余的和你一样我已经尝试了我能想到的几乎所有组合。如果我使用双引号设计路径(带