如何使用带空格的字符串插值在 bash 脚本中按程序生成命令?

如何使用带空格的字符串插值在 bash 脚本中按程序生成命令?

我正在尝试创建一个简单的脚本,该脚本使用如下所示的月份列表:

(一月二月)

要生成并执行此命令:

python ExpenseManager.py -p 输入/Jan\ 2019\ Debit.CSV 输入/Jan\ 2019\ Credit.CSV -p 输入/Feb\ 2019\ Debit.CSV 输入/Feb\ 2019\ Credit.CSV

这是我为此编写的程序:

#!/usr/bin/env bash
clear
months=(Jan Feb)
args=()
for month in ${months[@]}; do
  args=(${args[@]} -p "Inputs/${month}\\ 2019\\ Debit.CSV" "Inputs/${month}\\ 2019\\ Credit.CSV")
done
python ExpenseManager.py "${args[@]}"
exit 0

从理论上讲,这是有效的。当我回显结果命令时,我得到了我想要的确切命令:

python ExpenseManager.py -p 输入/Jan\ 2019\ Debit.CSV 输入/Jan\ 2019\ Credit.CSV -p 输入/Feb\ 2019\ Debit.CSV 输入/Feb\ 2019\ Credit.CSV

现在,当我复制/粘贴该程序创建的命令并执行它时,它工作正常。然而,当我让 Bash 执行该命令时,它包含了我用来在 Bash 中包含转义反斜杠的反斜杠:

命名空间(filepairs=[['输入/一月\', '2019\', '借记.CSV', '输入/一月\', '2019\', '信用.CSV'], ['输入/二月\ 2019 \ Debit.CSV', '输入/2019 年 2 月\ Credit.CSV']]

我尝试了几种解决方案来使其发挥作用:

  • 我尝试将参数设为单个字符串并以此为基础进行构建

  • 我尝试用单引号将参数括起来,并在空格周围使用双引号,如下所示:

args=(${args[@]} -p '输入/${月}" "2019" "Debit.CSV "输入/${月}" "2019" "Credit.CSV")

  • 我尝试使用引号分隔 arg 中需要空格的每个部分,如下所示:
  args=(${args[@]} -p "Inputs/${month}" "2019" "Debit.CSV" "Inputs/${month}\ 2019\ Credit.CSV")

我在这里和其他地方查看了其他解决方案,但似乎没有任何效果。因此,我不想继续陷入这个困境,而是希望有人能告诉我让 Bash 执行这个按程序构建的插值命令的魔术?

答案1

不要用来echo查看正在执行什么命令。它打印命令解析,即在应用引号和转义之后并删除);因此,如果 的输出echo包含引号和/或转义符,就像您期望在原始命令行中看到的那样(即在解析之前),则表明存在严重错误。比较这两个命令的输出echo

$ month=Jan
$ var="Inputs/${month}\\ 2019\\ Debit.CSV"
$ echo $var
Inputs/Jan\ 2019\ Debit.CSV
$ echo Inputs/Jan\ 2019\ Debit.CSV
Inputs/Jan 2019 Debit.CSV

首先,打印转义符,表明它们不是解析、应用和删除。在第二个例子中,他们消失了,表明他们解析、应用和删除。

那么,如何解决呢?两条规则:1) 不要在变量中添加引号或转义符(除非在奇怪的情况下字符串将经过额外级别的解析),2) 相反,请在所有变量引用周围添加双引号(包括${args[@]}) (再说一遍,有一些奇怪的例外)。另外,您可以使用 来添加到数组中array+=("new" "elements")

这是固定脚本:

#!/usr/bin/env bash
clear
months=(Jan Feb)
args=()
for month in "${months[@]}"; do
  args+=(-p "Inputs/${month} 2019 Debit.CSV" "Inputs/${month} 2019 Credit.CSV")
done
python ExpenseManager.py "${args[@]}"
exit 0

相关内容