我有一个包含用户列表的 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 更简洁的是使用getline
ex.:
$ 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(例如,它不会处理字段中嵌入的“,”字符)。