Bash 脚本将包含“和”的变量值写入文件

Bash script to write a variable value that contains " and ' to a file

提问人:AnjK 提问时间:6/1/2023 最后编辑:AnjK 更新时间:6/1/2023 访问量:148

问:

我正在创建一个 bash 脚本来将变量值写入 csv 文件。 但无法写入行中包含“和”符号的特定值。 例如,我在 shell 中提供了这样的变量和值:

用户名:[email protected]

名字:my-name

密码:j50z54"#7b'y'/3l7H%7

如果尝试将它们写入 csv 文件,如下所示:

  echo -e "username,password,name" >> abc.csv
  echo -e "$username,$password,$name" >> abc.csv

我收到错误:

line 2: unexpected EOF while looking for matching `"'
line 3: syntax error: unexpected end of file

由于值中存在双引号和单引号,因此会出现问题。

方法1:

按如下方式存储变量值:

  • 通过在双引号和单引号前面加上反斜杠来转义所有双引号和单引号 \
  • 将整个变量值括在双引号内。

例如,password 的实际值应另存为j50z54"#7b'y'/3l7H%7"j50z54\"#7b\'y\'/3l7H%7"

然后,如果我运行以下脚本:

  echo -e "username,password,name" >> abc.csv
  echo -e "$username,$password,$name" >> abc.csv
  sed -i 's/\\//g' abc.csv

我得到正确的csv文件:

username,password,name
[email protected],j50z54"#7b'y'/3l7H%7,my-name

但是,问题在于无法像上述格式那样修改变量值(在其源头)。

方法2:

我尝试了一个 metho,如图所示,脚本:

[email protected]
name=my-name
cat >> abc.csv << \EOF
Username,Password,Name
$username,j70z38"#7k'y'/3l7H%9,$name
EOF

给出输出文件 abc.csv:

Username,Password,Name
$username,j70z38"#7k'y'/3l7H%9,$name

(请忽略此处直接提供的密码值仅用于测试目的的事实)

在此方法中,将打印变量名称(如 $username 和 $name)而不是它们的值。

问题:

有没有其他更好的方法/脚本将变量值正确写入 CSV 文件?

附加信息:

此脚本用于在Azure DevOps管道的 bash 任务中实现自动化。此外,密码保存在变量组中,并在管道中作为 .$(password)

Linux Bash 文件 变量 Azure-DevOps

评论

3赞 Thomas 6/1/2023
您确定这是错误的原因吗?我可以在提示符上执行此操作:.password="j50z54\"#7b'y'/3l7H%7"; echo -e "$password"
0赞 Thomas 6/1/2023
通常 CSV 不用于转义引号。在大多数方言中,CSV 在字段两边使用双引号,然后使用双双引号 () 来表示字段中的单个双引号。\"""
1赞 Gordon Davisson 6/1/2023
您列出的命令不会导致“意外的 EOF”错误。问题出在其他地方,也许是你设置变量的地方,也许是因为脚本正在通过一些不寻常的解析过程运行(例如,通过一些自动化过程运行等)。一定要给出一个最小的可重现的例子来说明问题,这样我们就可以看到导致它所涉及的一切。echo
2赞 Gordon Davisson 6/1/2023
旁注:几乎总是一个错误;它是非标准的、不可移植的,并且容易出现意外行为。你真的希望它解释字符串中的反斜杠转义序列吗?如果没有,请使用例如 或。如果确实要解析转义序列,请在格式字符串中使用 INSTEAD。echo -eprintf '%s\n' "$username,$password,$name"printf '%s,%s,%s\n' "$username" "$password" "$name"%b%s
2赞 John Bollinger 6/1/2023
我认为我们需要一个真正的最小可重复的例子来证明你的问题,并描述实际和预期的结果。但是,我怀疑您在这里混淆了两个或多个层,例如数据在几个不同上下文中的表示方式。

答:

2赞 John Bollinger 6/1/2023 #1

将线索拼凑在一起,我认为您的情况大致如下:

  • 该脚本从某些外部源(参数、交互式输入、文件等)接收用户名、密码和名称,并将它们存储在变量中。

  • 您想要编写包含这些值的 CSV 表示形式的文件

  • 第一次尝试使用 ,将值写入为已接收值,但之后(单独的)CSV 读取器无法成功读回它们echo

  • 您的“方法 1”描述了一种概念验证变体,其中用户名、密码和名称是在脚本中显式设置的,而不是像最终需要的那样从外部源读取。

  • 您的“方法 2”可能是另一个概念验证变体

但是,我不接受这一点

无法写入行中包含“和”符号的特定值。

为支持该声明而提供的示例实际上完美地发出了这些值,并且,另外,您提供的错误消息不可能来自这些行。我最好的猜测是错误来自 CSV 读取器,在这种情况下,它反映的不是您未能写入数据,而是生成的文件不是有效的 CSV(就该读取器而言)。但是请注意,如果数据包含任何文字反斜杠 (),那么就会搞砸。如果您想使用(您可以),请删除 .\echo -eecho-e

此外,由于在未加引号的字段中包含双引号,某些 CSV 读取器会拒绝由方法 1 生成的文件,如果双引号出现在字段的开头而不是中间,则大多数 CSV 读取器会拒绝该文件。这可能是你所期望的,但按照大多数标准,它并没有很好地被描述为“正确”的 csv 文件。

您似乎正在努力解决的问题是 CSV 需要对某些字符进行特殊处理。您不能只是将原始字符数据转储到 CSV 文件中并期望读者理解它。您需要为 CSV 设置适当的数据格式。这与 Bash 无关。

另请注意,“CSV”范畴下的格式种类繁多。并非所有人都使用逗号作为字段分隔符。如果您以特定的 CSV 方言为目标,则需要根据该方言的要求设置输出格式。这肯定会包括对包含字段分隔符的字段进行某种形式的引用,并且很可能对包含引号字符的字段进行某种形式的引用。如果您的方言允许包含记录分隔符的字段,则它还需要引用这些字段。

如果您不确定您的 CSV 方言需要什么,或者您对此很灵活,那么请知道 CSV 方言主要使用双引号字符 () 进行引用,并且通常它们仅支持在整个字段的基础上引用。通常,在带引号的字段中转义双引号的指定方法是将其加倍。一些 CSV 方言希望所有字段都被引用,这与大多数方言兼容,所以除非你知道你需要做不同的事情,否则这就是我的建议。"

例:

#!/bin/bash

# Input the data
read -r -p 'username: ' username
read -r -p 'name: '     name
read -r -p 'password: ' password

# Double all quotation marks (") in the field values
username_csv=${username//\"/\"\"}
name_csv=${name//\"/\"\"}
password_csv=${password//\"/\"\"}

# Write the output file with quotes and field delimiters
cat >output.csv <<EOF
Username,Password,Name
"$username_csv","$password_csv","$name_csv"
EOF

演示

$ bash example.sh
username: [email protected]
name: my-name
password: j50z54"#7b'y'/3l7H%7
$
$ cat output.csv
Username,Password,Name
"[email protected]","j50z54""#7b'y'/3l7H%7","my-name"

评论

0赞 AnjK 6/1/2023
这奏效了。非常感谢。我这边的主要错误之一是在方法 2 行中:。那里不需要之前的反斜杠。我删除了它,然后脚本使用了.cat >> abc.csv << \EOFEOFcat >> abc.csv << EOF