[英]Randomly generating invoice IDs - moving text database into script file?
I've come up with the following bash
script to randomly generate invoice numbers, preventing duplications by logging all generated numbers to a text file "database".我想出了以下
bash
脚本来随机生成发票编号,通过将所有生成的编号记录到文本文件“数据库”来防止重复。
To my surprise the script actually works, and it seems robust (although I'd be glad to have any flaws pointed out to me at this early stage rather than later on).令我惊讶的是,该脚本确实有效,而且看起来很健壮(尽管我很高兴在这个早期阶段而不是以后向我指出任何缺陷)。
What I'm now wondering is whether it's at all possible to move the "database" of generated numbers into the script file itself.我现在想知道的是,是否有可能将生成数字的“数据库”移动到脚本文件本身中。 This would allow me to rely on and keep track of just the one file rather than two separate ones.
这将允许我只依赖和跟踪一个文件,而不是两个单独的文件。
Is this at all possible, and if so, how?这有可能吗?如果有,怎么做? If it isn't a good idea, what valid reasons are there not to do so?
如果这不是一个好主意,那么有什么正当理由不这样做呢?
#!/usr/bin/env bash
generate_num() {
#num=$(head /dev/urandom | tr -dc '[:digit:]' | cut -c 1-5) [Original method, no longer used]
num=$(shuf -i 10000-99999 -n 1)
}
read -p "Are you sure you want to generate a new invoice ID? [Y/n] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
generate_num && echo Generating a random invoice ID and checking it against the database...
sleep 2
while grep -xq "$num" "ID_database"
do
echo Invoice ID \#$num already exists in the database...
sleep 2
generate_num && echo Generating new random invoice ID and checking against database...
sleep 2
done
while [[ ${#num} -gt 5 ]]
do
echo Invoice ID \#$num is more than 5 digits...
sleep 2
generate_num && echo Generating new random invoice ID and checking against database...
sleep 2
done
echo Generated random invoice ID \#$num
sleep 1
echo Invoice ID \#$num does not exist in database...
sleep 2
echo $num >> "ID_database" && echo Successfully added Invoice ID \#$num to the database.
else
echo "Exiting..."
fi
To answer the question you asked -要回答您提出的问题-
Make sure your file ends with an explicit exit
statement.确保您的文件以明确的
exit
语句结尾。 Without some sort of branching it won't execute past that, so unless there is a gross parsing error anything below could be used as storage space.如果没有某种分支,它将无法执行,因此除非存在严重的解析错误,否则下面的任何内容都可以用作存储空间。 Just
只是
echo $num >> $0
If you write your records directly onto the bottom of the script, the script grows, but...relatively harmlessly.如果您将记录直接写到脚本的底部,脚本会增长,但是……相对无害。 Just make sure your
grep
pattern doesn't grab any lines of code, though grep -E '^\d[%]$'
seems pretty safe.只需确保您的
grep
模式不会抓取任何代码行,尽管grep -E '^\d[%]$'
似乎很安全。
This is only ever going to give you a max of ~90k id's, and spends unneeded time and cycles on redundancy checking.这只会给您最多约 90k 的 id,并且会花费不必要的时间和周期进行冗余检查。 Is there a limit on the length of the value?
值的长度有限制吗?
If you can assure there won't be more than one invoice processed per second,如果您能保证每秒处理的发票不会超过一张,
date +%s >> "ID_database" # the UNIX epoch, seconds since 00:00:00 01/01/1970
If you need more precision that that,如果您需要更高的精度,
date +%Y%m%d%H%M%S%N
will output Year month day hour minute second nanoseconds, which is both immediate and "pretty safe".将 output 年月日时分秒纳秒,既即时又“非常安全”。
date +%s%N # epoch with nanoseconds
is shorter, but doesn't have the convenient side effect of automatically giving you the date and time of invoice creation.更短,但没有自动为您提供发票创建日期和时间的便利副作用。
If you absolutely need to guarantee uniqueness and nanoseconds isn't good enough, use a lock of some sort, and maybe a more fine-grained language.如果您绝对需要保证唯一性并且纳秒还不够好,请使用某种锁,也许是更细粒度的语言。
On the other hand, if minutes are unique enough , you could use另一方面,如果分钟足够独特,您可以使用
date +%y%m%d%H%M
You get the idea.你明白了。
I do not recommend this because:我不推荐这个,因为:
"$mydir"
is an empty directory when you run the script (except for "$myname"
, .git
and other git -related files) then run git -C "$mydir" init
if "$mydir"/.git
doesn't exist."$mydir"
是一个空目录( "$myname"
、. .git
和其他git相关文件除外)然后运行git -C "$mydir" init
如果"$mydir"/.git
不存在。 Then for each database update, git -C "$mydir" add "$myname"
and git -C "$mydir" commit -m "$num"
.git -C "$mydir" add "$myname"
和git -C "$mydir" commit -m "$num"
。 It's just an idea to explore... ... but you want a self-modifying script, so here goes. ...但是您想要一个自修改脚本,所以就这样吧。
This just adds a new invoice number to its internal database for each time you run it.这只是在您每次运行时将一个新的发票编号添加到其内部数据库中。 I've explained what goes on as comments.
我已经解释了评论的内容。 The last line should read
__INVOICES__
(+ a newline) if you copy the script.如果您复制脚本,最后一行应为
__INVOICES__
(+ 换行符)。
As always when dealing with things like this, remember to make a backup before making changes:-)与往常一样,在处理此类事情时,请记住在进行更改之前进行备份:-)
As it's currently written, you can only add one invoice per run.正如目前所写,每次运行只能添加一张发票。 It shouldn't be hard to move things around (you need a new tempfile) to get it to add more than one if you need that.
如果需要的话,移动东西应该不难(你需要一个新的临时文件)让它添加多个。
#!/bin/bash
set -e # exit on error - imporant for this type of script
#------------------------------------------------------------------------------
myname="$0"
mydir=$(dirname "$myname")
if [[ ! -w $myname ]]; then
echo "ERROR: You don't have permission to update $myname" >&2
exit 1
fi
# create a tempfile to be able to update the database in the file later
#
# set -e makes the script end if this fails:
temp=$(mktemp -p "$mydir")
trap "{ rm -f "$temp"; }" EXIT # remove the tempfile if we die for some reason
# read current database from the file
readarray -t ID_database <<< $(sed '0,/^__INVOICES__$/d' "$0")
#declare -p ID_database >&2 # debug
#------------------------------------------------------------------------------
# a function to check if a number is already in the db
is_it_taken() {
local num=$1
# return 1 (true, yes it's taken) if the regex found a match
[[ ! " ${ID_database[@]} " =~ " ${num} " ]]
}
generate_num() {
local num
(exit 1) # set $? to 1
# loop until $? becomes 0
while (( $? )); do
num=$(shuf -i 10000-99999 -n 1)
is_it_taken "$num"
done
# we found a free number
echo $num
}
add_to_db() {
local num=$1
# add to db in memory
ID_database+=($num)
# add to db in file:
# copy the script to the tempfile
cp -pf "$myname" "$temp"
# add the new number
echo $num >> "$temp"
# move the tempfile into place
mv "$temp" "$myname"
}
#------------------------------------------------------------------------------
num=$(generate_num)
add_to_db $num
# your business logic goes here:
echo "All current invoices:"
for invoice in ${ID_database[@]}
do
echo ">$invoice<"
done
#------------------------------------------------------------------------------
# leave the rest untouched:
exit
__INVOICES__
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.