将具有随机值的列添加到 CSV 末尾

将具有随机值的列添加到 CSV 末尾

我有一个包含用户列表的 CSV,并且想添加一列,其中包含一次性随机生成的密码,该密码对于每个用户都是唯一的。

我的脚本有效...但它只是继续无限期地添加行。如果我将代码移出循环以设置变量,它就可以正常工作,但每个用户都会获得相同的密码。

如何让它在最后一行终止?

#!/bin/bash
#add column to csv
ORIG_FILE="new-users2.csv"
NEW_FILE="Output.csv"
{ echo `head -1 $ORIG_FILE`",One Time Password" ; tail -n +2 $ORIG_FILE | \
  while read x ; OneTimePass=$(openssl rand -base64 14 | head -c 6) ; do echo "$x,$OneTimePass" ; done ; } > $NEW_FILE

答案1

您的循环语法while...do...done错误。你正在运行这个:

while read x ; OneTimePass=$(openssl rand -base64 14 | head -c 6) ; do ...

关键字while的预期格式解释如下help while

$ help while
while: while COMMANDS; do COMMANDS; done
    Execute commands as long as a test succeeds.
    
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.
    
    Exit Status:
    Returns the status of the last command executed.

在这里,您给它两个命令:read x ;OneTimePass=$(openssl rand -base64 14 | head -c 6),第二个命令始终有效,它没有任何结尾,因为您始终可以重新运行该openssl命令。这就是为什么while循环永远不会退出,而你只是不断地写越来越多的行。你所追求的是这样的:

while read x; do
    something
done

这是脚本的工作版本,其中包含一些其他改进,例如正确引用和避免变量名大写:

#!/bin/bash

#add column to csv
orig_file="new-users2.csv"
new_file="Output.csv"

printf "%s,%s\n" "$(head -1 "$orig_file")" "One Time Password" > "$new_file"
tail -n +2 "$orig_file" |
  while read -r x; do
    OneTimePass="$(openssl rand -base64 14 | head -c 6)"
    printf '%s,%s\n' "$x" "$OneTimePass"
  done >> "$new_file"

就我个人而言,我会避免对文件名进行硬编码,因为这会使脚本更难使用且通用性较差。我会将输入文件名作为参数,然后打印到标准输出,以便您可以选择所需的任何输出文件:

#!/bin/bash

#add column to csv
orig_file=$1

printf "%s,%s\n" "$(head -1 "$orig_file")" "One Time Password"
tail -n +2 "$orig_file" |
  while read -r x; do
    OneTimePass="$(openssl rand -base64 14 | head -c 6)"
    printf '%s,%s\n' "$x" "$OneTimePass"
  done

然后你可以像这样运行它:

foo.sh new-users2.csv > Output.csv 

我用这个输入文件进行了测试:

$ cat new-users2.csv 
name,age
Bob,45
Alice,36

结果是:

$ foo.sh new-users2.csv 
name,age,One Time Password
Bob,45,BTkLQW
Alice,36,CzQa4U

答案2

使用磨坊主,并且厚颜无耻地借用@terdon 的示例文件

$ mlr --csv put -S '
    $["One Time Password"] = substr(system("openssl rand -base64 5"),0,5)
' new-users2.csv 
name,age,One Time Password
Bob,45,kIrlrl
Alice,36,h1OBp3

(我将openssl rand参数从 14 字节更改为 5 字节,因为生成 6 个 Base64 字符不需要超过 36 位。如果由于某种原因它很重要,请将其更改回来。)

您可以使用 awk 的system()函数执行类似的操作,但 CSV 结构和标头的处理更加混乱。也许使用 awk 更简洁的是使用getlineex.:

$ awk -F, '
    BEGIN {OFS=FS; cmd = "openssl rand -base64 5"} 
    NR==1 {$(NF+1) = "One Time Password"} 
    NR >1 {cmd | getline var; close(cmd); $(NF+1) = substr(var,1,6)} 
    1
' new-users2.csv
name,age,One Time Password
Bob,45,CovLkz
Alice,36,PgLbD4

与 Miller 版本不同,这仅适用于“简单”CSV(例如,它不会处理字段中嵌入的“,”字符)。

相关内容