【问题标题】:How to escape a variable in Bash when passing to a command-line argument传递给命令行参数时如何在 Bash 中转义变量
【发布时间】:2013-06-19 21:24:47
【问题描述】:

我有一个 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 变量,但我真的不知道我在用它做什么,似乎也无法让它与它一起工作,尽管我怀疑该解决方案与 $国际金融服务公司。

【问题讨论】:

  • 您是否尝试过双重转义空格?例如。 Documents\\\ and\\\
  • 我试过了,但遇到了几个问题:1)我的 mv 不起作用,因为它试图将文件移动到 Documents\\ 和 \\ (即:bash 吞下一个escape),然后电子邮件表达式中 $args 的扩展变为: -a '/cygdrive/c/Documents\' 'and\' 'Settings/Eric/My\' Documents/AJ/CSS//2013-06- 21.pdf。在每个空间中,多个 ' 的 b/c 不起作用。
  • 也许您可以将destinationPath 带入双引号并删除转义空格?和你一样休息
  • 我已经尝试了几乎所有我能想到的组合。如果我使用双引号 desinationPath(没有转义字符串),则电子邮件扩展不带引号,然后再次中断。我已经使用功能齐全的示例脚本编辑了我的原始问题。
  • 大胆猜测,但请尝试将$destinationPath/$file 替换为\"$destinationPath/$file\",看看是否有帮助

标签: bash variables escaping ifs


【解决方案1】:

没有数组就没有好办法。 (有一个不好的方法,使用eval,但是数组更简单。)

问题是您希望每个文件最终都作为email 的一个参数,但您希望将所有这些参数累积到一个 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

您可能还想将attachments 变量放入一个数组中;从换行符的存在来看,我假设您实际上是在以更复杂的方式设置它,所以我没有更改代码。但是,如果附件名称中有空格,则您当前的代码将不起作用(而且我很确定 for 表单中的参数扩展将消除换行符,除非您更改了 @ 的值987654328@,所以file=${file//[ \\n]/} 不是必须的。)

【讨论】:

  • 谢谢。会试一试的。我不知道/意识到 Bash 支持数组。至于将附件制作成数组,我非常喜欢,但我需要将其扩展到我的电子邮件正文中,每个附件名称一行。将研究如何轻松完成这项工作。
  • 优秀。像魅力一样工作!需要学习如何在 Bash 中更好地使用数组。谢谢!
【解决方案2】:

在字符串中提供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

【讨论】:

  • 这不起作用,因为 bash 在替换变量之前确实会转义和引用解释,所以如果你将转义/引号/etc in 变量放入它们永远不会生效(通过当变量被扩展时,他们做任何事情都为时已晚)。数组(如@rici 的回答)是做这类事情的最佳方式。
猜你喜欢
  • 1970-01-01
  • 2023-04-03
  • 2014-09-13
  • 2016-05-31
  • 2014-12-04
  • 2017-06-15
  • 1970-01-01
  • 2012-10-21
相关资源
最近更新 更多