繁体   English   中英

随机生成发票 ID - 将文本数据库移动到脚本文件中?

[英]Randomly generating invoice IDs - moving text database into script file?

我想出了以下bash脚本来随机生成发票编号,通过将所有生成的编号记录到文本文件“数据库”来防止重复。

令我惊讶的是,该脚本确实有效,而且看起来很健壮(尽管我很高兴在这个早期阶段而不是以后向我指出任何缺陷)。

我现在想知道的是,是否有可能将生成数字的“数据库”移动到脚本文件本身中。 这将允许我只依赖和跟踪一个文件,而不是两个单独的文件。

这有可能吗?如果有,怎么做? 如果这不是一个好主意,那么有什么正当理由不这样做呢?

#!/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

已编辑

要回答您提出的问题-

确保您的文件以明确的exit语句结尾。 如果没有某种分支,它将无法执行,因此除非存在严重的解析错误,否则下面的任何内容可以用作存储空间。 只是

echo $num >> $0

如果您将记录直接写到脚本的底部,脚本会增长,但是……相对无害。 只需确保您的grep模式不会抓取任何代码行,尽管grep -E '^\d[%]$'似乎很安全。


这只会给您最多约 90k 的 id,并且会花费不必要的时间和周期进行冗余检查。 值的长度有限制吗?

如果您能保证每秒处理的发票不会超过一张,

date +%s >> "ID_database" # the UNIX epoch, seconds since 00:00:00 01/01/1970

如果您需要更高的精度,

date +%Y%m%d%H%M%S%N

将 output 年月日时分秒纳秒,既即时又“非常安全”。

date +%s%N # epoch with nanoseconds

更短,但没有自动为您提供发票创建日期和时间的便利副作用。

如果您绝对需要保证唯一性并且纳秒还不够好,请使用某种锁,也许是更细粒度的语言。

另一方面,如果分钟足够独特,您可以使用

 date +%y%m%d%H%M

你明白了。

我不推荐这个,因为:

  • 这些东西很脆弱。 一次错误的编辑,您的发票数据库已损坏。
  • 它使版本控制变得很痛苦。 最好签入脚本的每个新版本。您可以添加逻辑以确保在运行脚本时"$mydir"是一个空目录( "$myname" 、. .git和其他相关文件除外)然后运行git -C "$mydir" init如果"$mydir"/.git不存在。 然后对于每个数据库更新, git -C "$mydir" add "$myname"git -C "$mydir" commit -m "$num" 这只是一个探索的想法......
  • 锁定 - 可以进行文件锁定以确保不是两个用户同时运行脚本,但它增加了复杂性,所以我没有打扰。 如果你觉得这是一个风险,你需要添加它。

...但是您想要一个自修改脚本,所以就这样吧。

这只是在您每次运行时将一个新的发票编号添加到其内部数据库中。 我已经解释了评论的内容。 如果您复制脚本,最后一行应为__INVOICES__ (+ 换行符)。

与往常一样,在处理此类事情时,请记住在进行更改之前进行备份:-)

正如目前所写,每次运行只能添加一张发票。 如果需要的话,移动东西应该不难(你需要一个新的临时文件)让它添加多个。

#!/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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM