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

Database 随机生成发票ID-将文本数据库移动到脚本文件中?,database,bash,shell,random,git,Database,Bash,Shell,Random,Git,我提出了以下bash脚本来随机生成发票编号,通过将所有生成的编号记录到文本文件“数据库”中来防止重复 令我惊讶的是,这个脚本确实有效,而且看起来很健壮(尽管我很高兴在这个早期阶段,而不是以后,有人向我指出任何缺陷) 我现在想知道的是,是否有可能将生成的数字的“数据库”移动到脚本文件本身。这将允许我只依赖并跟踪一个文件,而不是两个单独的文件 这可能吗?如果可能,怎么可能?如果这不是一个好主意,有什么正当理由不这样做 #!/usr/bin/env bash generate_num() { #nu

我提出了以下
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[%]$'
看起来相当安全

date +%s%N # epoch with nanoseconds

这只会给您提供最多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
将输出年-月-日-小时-分-秒纳秒,这是即时的和“非常安全的”

较短,但没有自动提供发票创建日期和时间的方便副作用

如果您确实需要保证唯一性,而纳秒还不够好,请使用某种类型的锁,或者使用更细粒度的语言

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

 date +%y%m%d%H%M
你明白了。

回答你的问题-

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

echo $num >> $0
如果您将记录直接写入脚本的底部,脚本将增长,但……相对无害。只需确保您的
grep
模式不会捕获任何代码行,尽管
grep-E'^\d[%]$'
看起来相当安全

date +%s%N # epoch with nanoseconds

这只会给您提供最多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
将输出年-月-日-小时-分-秒纳秒,这是即时的和“非常安全的”

较短,但没有自动提供发票创建日期和时间的方便副作用

如果您确实需要保证唯一性,而纳秒还不够好,请使用某种类型的锁,或者使用更细粒度的语言

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

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

你明白了。

我不建议这样做,因为:

  • 这些东西易碎。一次错误的编辑,您的发票数据库已损坏
  • 它使版本控制成为一种痛苦。最好签入脚本的每个新版本。您可以添加逻辑以确保在运行脚本时
    “$mydir”
    是空目录(除了
    “$myname”
    .git
    和其他相关文件),然后在
    “$mydir”/.git
    不存在的情况下运行
    git-C“$mydir”init
    。然后,对于每个数据库更新,
    git-C“$mydir”添加“$myname”
    git-C“$mydir”commit-m“$num”
    。这只是一个探索的想法
  • 锁定-可以进行文件锁定,以确保不是两个用户同时运行脚本,但这增加了复杂性,所以我不必费心。如果你觉得这是一个风险,你需要补充
。。。但是你需要一个自我修改的脚本,所以这里开始

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

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

正如当前编写的,每次运行只能添加一张发票。如果需要的话,移动一些东西(您需要一个新的tempfile)让它添加多个tempfile应该不难

#!/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__
#/bin/bash
set-e#出错时退出-对于这种类型的脚本很重要
#------------------------------------------------------------------------------
myname=“$0”
mydir=$(dirname“$myname”)
如果[!-w$myname]];然后
echo“错误:您没有更新$myname的权限”>&2
出口1
fi
#创建一个临时文件,以便以后能够更新文件中的数据库
#
#如果失败,set-e将结束脚本:
温度=$(mktemp-p“$mydir”)
陷阱“{rm-f“$temp”;}”退出#如果我们因为某种原因死亡,请删除temp文件
#从文件中读取当前数据库

readarray-t ID_数据库我不建议这样做,因为:

  • 这些东西易碎。一次错误的编辑,您的发票数据库已损坏
  • 它使版本控制成为一种痛苦。最好签入脚本的每个新版本。您可以添加逻辑以确保在运行脚本时
    “$mydir”
    是空目录(除了
    “$myname”
    .git
    和其他相关文件),然后在
    “$mydir”/.git
    不存在的情况下运行
    git-C“$mydir”init