Bash脚本将包含"和'的变量值写入文件中

huangapple go评论75阅读模式
英文:

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

问题

I'm creating a bash script to write variable values to a csv file.
But unable to write particular values that contain " and ' symbols in the line.
For example, I have variables and values like this available into the shell:

username: my-name@abc.com

name: my-name

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

If try to write them to a csv file like this:

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

I get an error:

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

The problem occurs due to the presence of double quotes and single quotes in the value.

Method 1:

Store the variable value as follows:

  • escape all double quotes and single quotes by prepending them with a backslash \
  • enclose the entire variable value within double quotes.

For example, an actual value of password j50z54"#7b'y'/3l7H%7 should be saved as "j50z54\"#7b\'y\'/3l7H%7"

Then if I run the following script:

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

I get the proper csv file:

username,password,name
my-name@abc.com,j50z54"#7b'y'/3l7H%7,my-name

BUT, the problem is that it is not possible to modify the variable value ( at its source ) as in the above-mentioned format.

Method 2:

I tried a method as shown here, the script:

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

gives output file abc.csv:

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

(please ignore the fact that password value is directly provided here for just testing purposes)

In this method, variable names like $username and $name are printed instead of their values.

Question:

Is there any other better way/script to write the variable value properly to a CSV file?

ADDITIONAL INFORMATION:

This script is used for automation inside a bash task of the Azure DevOps pipeline. Also, the password is saved in a variable group there and is available inside the pipeline as $(password).

英文:

I'm creating a bash script to write variable values to a csv file.
But unable to write particular values that contain " and ' symbols in the line.
For example, I have variables and values like this available into the shell:

username: my-name@abc.com

name: my-name

password: j50z54&quot;#7b&#39;y&#39;/3l7H%7

If try to write them to a csv file like this:

  echo -e &quot;username,password,name&quot; &gt;&gt; abc.csv
  echo -e &quot;$username,$password,$name&quot; &gt;&gt; abc.csv

I get an error:

line 2: unexpected EOF while looking for matching `&quot;&#39;
line 3: syntax error: unexpected end of file

Thre problem occurs due to the presence of double quotes and single quotes in the value.

Method 1:

Store the variable value as follows:

  • escape all double quotes and single quotes by prepending them with a backslash \
  • enclose the entire variable value within double quotes.

For example, an actual value of password j50z54&quot;#7b&#39;y&#39;/3l7H%7 should be saved as &quot;j50z54\&quot;#7b\&#39;y\&#39;/3l7H%7&quot;

Then if I run the following script:

  echo -e &quot;username,password,name&quot; &gt;&gt; abc.csv
  echo -e &quot;$username,$password,$name&quot; &gt;&gt; abc.csv
  sed -i &#39;s/\\//g&#39; abc.csv

I get the proper csv file:

username,password,name
my-name@abc.com,j50z54&quot;#7b&#39;y&#39;/3l7H%7,my-name

BUT, the problem is that it is not possible to modify the variable value ( at its source ) as in the above-mentioned format.

Method 2:

I tried a metho as shown here, the script:

username=my-name@abc.com
name=my-name
cat &gt;&gt; abc.csv &lt;&lt; \EOF
Username,Password,Name
$username,j70z38&quot;#7k&#39;y&#39;/3l7H%9,$name
EOF

gives output file abc.csv:

Username,Password,Name
$username,j70z38&quot;#7k&#39;y&#39;/3l7H%9,$name

(please ignore the fact that password value is directly provided here for just testing purposes)

In this method, variable names like $username and $name are printed instead of their values.

Question:

Is there any other better way/script to write the variable value properly to a CSV file?

ADDITIONAL INFORMATION:

This script is used for automation inside a bash task of the Azure DevOps pipeline. Also, the password is saved in a variable group there and is available inside the pipeline as $(password).

答案1

得分: 2

拼凑线索,我认为你的情况大致如下:

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

  • 你想要编写一个包含这些值的CSV表示的文件。

  • 你的第一个尝试,使用echo,将接收到的值写入文件,但是你的CSV读取器不能成功读取它们。

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

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

然而,我不同意这一点:

无法写入包含“和'符号的特定值。

事实上,支持这一主张的示例完美地输出这些值,并且,分开看,你呈现的错误消息不可能来自这些行。我最好的猜测是错误来自于一个CSV读取器,如果是这种情况,它反映的不是你未能写入数据,而是生成的文件在该读取器看来不是有效的CSV(就读取器而言)。不过,要注意,如果数据包含任何字面上的反斜杠字符(\),那么echo -e会弄乱它。如果你想使用echo(你可以这样做),那就不要使用-e

此外,使用你的方法1生成的文件可能会被一些CSV读取器拒绝,因为它包含一个未加引号的字段中的双引号,如果双引号出现在字段的开头而不是中间,大多数CSV读取器都会拒绝它。它可能是你预期的内容,但在大多数标准中,它不能很好地被定义为一个“正确”的CSV文件。

你似乎遇到的问题是CSV需要对某些字符进行特殊处理。你不能只是将原始字符数据倒入CSV文件中,然后期望读取器能够理解它。**你需要适当地格式化数据以适应CSV。**这与Bash没有直接关系。

还要注意,CSV伞下有多种格式,其中并非所有都使用逗号作为字段分隔符。如果你针对特定的CSV方言,那么你需要按照该方言的要求格式化输出。这通常包括对包含字段分隔符的字段进行引用,以及对包含引号字符的字段进行引用。如果你的方言允许包含记录分隔符的字段,那么它也需要将这些字段引用起来。

如果你不确定你的CSV方言需要什么,或者如果你在这方面有灵活性,那么要知道,CSV方言主要使用双引号字符(")进行引用,并且通常只支持整个字段的引用。通常,在引用字段内部的双引号的指定方式是将其重复一次。一些CSV方言期望所有字段都被引用,这与大多数方言兼容,所以除非你知道需要做出不同的选择,否则我建议这样做。

示例:

#!/bin/bash

# 输入数据
read -r -p '用户名: ' 用户名
read -r -p '姓名: ' 姓名
read -r -p '密码: ' 密码

# 在字段值中重复所有引号(")
用户名_CSV=${用户名//\"/\"\"}
姓名_CSV=${姓名//\"/\"\"}
密码_CSV=${密码//\"/\"\"}

# 使用引号和字段分隔符写入输出文件
cat >输出.csv <<EOF
用户名,密码,姓名
"$用户名_CSV","$密码_CSV","$姓名_CSV"
EOF

演示:

$ bash 示例.sh
用户名: my-name@abc.com
姓名: my-name
密码: j50z54"#7b'y'/3l7H%7
$
$ cat 输出.csv
用户名,密码,姓名
"my-name@abc.com","j50z54""#7b'y'/3l7H%7","my-name"
英文:

Piecing together the clues, I think your situation is something along these lines:

  • the script receives the username, password, and name from some external source (arguments, interactive input, file ...) and stores them in variables.

  • you want to write a file containing CSV representations of those values

  • your first attempt, with echo, writes the values as received, but your (separate) CSV reader cannot read them back successfully afterward

  • your "Method 1" describes a proof-of-concept variation in which the username, password, and name are set explicitly in the script, instead of being read from an external source as they ultimately need to be.

  • your "Method 2" is presumably another proof-of-concept variation

However, I do not accept this:

> unable to write particular values that contain " and ' symbols in the line.

The example presented to support that claim in fact emits such values flawlessly, and, separately, the error message you present cannot have come from those lines. My best guess is that the error comes from a CSV reader, in which case it reflects not that you failed to write the data, but that the resulting file was not valid CSV (as far as that reader was concerned). Do note, however, that if the data contained any literal backslashes (\) then echo -e would screw that up. If you want to use echo (which you could) then drop the -e.

Additionally, the file resulting from your method 1 would be rejected by some CSV readers on account of containing a double quote in an unquoted field, and it would be rejected by most CSV readers if the double quote appeared at the beginning of the field instead of in the middle. It may be what you expected, but it is not well characterized as a "proper" csv file by most standards.

The issue you seem to be struggling with is that CSV requires special handling for some characters. You cannot just dump raw character data into a CSV file and expect readers to understand it. You need to format the data appropriately for CSV. This has nothing specifically to do with Bash.

Note also that there is a pretty big diversity of formats that fall under the "CSV" umbrella. Not all of them even use commas as field delimiters. If you are targeting a specific CSV dialect then you will need to format your output as that dialect requires. That will surely include some form of quoting for fields that include the field delimiter, and very likely some form of quoting for fields that include the quoting character(s). If your dialect allows fields that contain the record delimiter, then it will also require those fields to be quoted.

If you're not sure what your CSV dialect requires, or if you're flexible about that, then know that CSV dialects predominantly use the double-quote character (&quot;) for quoting, and generally they support quoting only on a whole-field basis. And typically, the designated means for escaping a double quote inside a quoted field is to double it. Some CSV dialects expect all fields to be quoted, and that's compatible with most dialects, so unless you know that you need to do differently, that's what I would recommend.

Example:

#!/bin/bash

# Input the data
read -r -p &#39;username: &#39; username
read -r -p &#39;name: &#39;     name
read -r -p &#39;password: &#39; password

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

# Write the output file with quotes and field delimiters
cat &gt;output.csv &lt;&lt;EOF
Username,Password,Name
&quot;$username_csv&quot;,&quot;$password_csv&quot;,&quot;$name_csv&quot;
EOF

Demo

$ bash example.sh
username: my-name@abc.com
name: my-name
password: j50z54&quot;#7b&#39;y&#39;/3l7H%7
$
$ cat output.csv
Username,Password,Name
&quot;my-name@abc.com&quot;,&quot;j50z54&quot;&quot;#7b&#39;y&#39;/3l7H%7&quot;,&quot;my-name&quot;

huangapple
  • 本文由 发表于 2023年6月1日 01:58:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376179.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定