同步数据库两表脚本(逻辑有点小问题):

#!/bin/bash

SRC_SCHEMA="xxx_xx"
SRC_TABLE="xx_xxx"
DES_SCHEMA="xx_xx"
DES_TABLE="xx_xx"
FIELDS="**,****,***,***"

function commit () {
    psql -d postgres -h 132.46.***.30 -p 5*** -U user_xx -c "$1"
}

function check() {
    result_lines=`commit "select count(1) from $DES_SCHEMA.$DES_TABLE" | sed -n '3p' | sed s/[[:space:]]//g`
    src_lines=`commit "select count(1) from $SRC_SCHEMA.$SRC_TABLE" | sed -n '3p' | sed s/[[:space:]]//g`

    if [ $result_lines -eq $src_lines ];then
        return 0; else
        return 1
    fi
}

function print_log() {
    echo `date "+%Y-%m-%d %H:%M:%S"` : $1
}

function main() {
    if ( check );then
        print_log "数据未变化,不做任何操作…"; else
        print_log "数据发生变化,准备同步数据…"
        print_log "清空数据表…"
        commit "truncate $DES_SCHEMA.$des_table"
        print_log "同步数据…"
        commit "insert into $DES_SCHEMA.$DES_TABLE select $FIELDS from $SRC_SCHEMA.$SRC_TABLE"
        print_log "插入数据完成…准备检测数据"
        if ( check );then
            print_log "数据同步完成!"; else
            print_log "数据同步失败,请管理员确认!"
        fi
    fi
}

main

检查程序是否启动,如果启动则关闭重启,否则启动:

#!/bin/bash

PID=`ps -ef | grep dontstarve_dedi | grep -v grep | grep -v PPID | awk '{ print $2 }'`
STEAMCMD_DIR="/root/steamcmd"
DST_DIR="~/Steam/steamapps/common/Don\'t\ Starve\ Together\ Dedicated\ Server"

function update() {
    print_log "更新..."
    $STEAMCMD_DIR/steamcmd.sh +login anonymous +force_install_dir /home/steam/dst +app_update 343050 validate +quit
    $DST_DIR/dontstarve_dedicated_server_nullrenderer -only_update_server_mods
    print_log "更新完毕!"
}

function start_game() {
    read -p "是否更新游戏与MOD[y/n]:" key
    case $key in
        'y')
            update
            ;;
        *)
            print_log "不执行任何操作"
            ;;
    esac
    print_log "启动游戏"
    ~/script/start_master.sh
    ~/script/start_caves.sh
}

function print_log() {
    echo $1
}

function kill_pid() {
    print_log "强制重启游戏中..."
    for i in $PID; do
        kill -9 $i
    done
    screen -wipe > /dev/null 2>&1
}

function check() {
    if [ -z "$PID" ];then
        start_game; else
        read -p "饥荒已启动,是否强制重启[y/n](存档可能会损坏!!!):" key
        case $key in
            'y')
                kill_pid
                start_game
                ;;
            *)
                print_log "不执行任何操作"
                ;;
        esac
    fi
}

function main() {
    check
}

main

饥荒专用服务器启动脚本:

#!/bin/bash

# By BayMin.

PID=`ps -ef | grep dontstarve_dedi | grep -v grep | grep -v PPID | awk '{ print $2 }'`
SCRIPT_DIR=$(cd `dirname $0`;pwd)
DOC_FILE="$SCRIPT_DIR/world_set/"
STEAMCMD_DIR="NULL/steamcmd"
DST_DIR="NULL/dst"
UPDATE_PARAM="validate"
CLUSTER="MyDediServer"
# 脚本中无法使用~,使用NULL获取
KLEI_DIR="NULL/.klei/DoNotStarveTogether"
CLUSTER_INI_A=(game_mode max_players pvp pause_when_empty lan_only_cluster cluster_intention cluster_password cluster_description cluster_name offline_cluster cluster_language console_enabled shard_enabled bind_ip master_ip master_port cluster_key)
SERVER_INI_MASTER_A=(server_port is_master encode_user_path)
SERVER_INI_CAVES_A=(server_port is_master name id encode_user_path master_server_port authentication_port)
DEFAULT_ADMIN_A=(KU_EnIZn3Fg KU_sNBlyMqO KU_NZlUgktT KU_u0cSuVm7)
DEFAULT_MOD_A=(1216718131 703758203 378160973 666155465)

function print_log() {
    case $2 in 
        'black')
            color="30m"
            ;;
        'red')
            color="31m"
            ;;
        'green')
            color="32m"
            ;;
        'yellow')
            color="33m"
            ;;
        'blue')
            color="34m"
            ;;
        'purple')
            color="35m"
            ;;
        'azure')
            color="36m"
            ;;
        'white')
            color="37m"
            ;;
        *)
            color=""
            ;;
    esac

    if [ -z $color ]; then
        echo -e "\n $1 "; else
        echo -e "\033[$color\n $1 \033[0m"
    fi
}

function update() {
    print_log "更新游戏..." "green"
    $STEAMCMD_DIR/steamcmd.sh +login anonymous +force_install_dir $DST_DIR +app_update 343050 $UPDATE_PARAM +quit
    print_log "更新MOD..." "green"
    cd $DST_DIR/bin
    # 此处启动饥荒服务器时必须进入饥荒服务器文件夹中的bin目录中,否则无法会报无法切换至../data文件的错误
    ./dontstarve_dedicated_server_nullrenderer -only_update_server_mods
    print_log "更新完毕!" "yellow"
}

function add_mods() {
    while (true)
    do
        print_log ""
        read -p " 请输入MOD编号(终止输入请输入ok):" mod_id
        case $mod_id in
            'ok')
                break
                ;;
            *)
                if [ ! -n "$(echo $mod_id | sed -n "/^[0-9]\+$/p")" ]; then
                    print_log " 请输入纯数字!!!(可在创意工坊连接上找到对应ID)" "red"
                    continue
                fi
                MOD_IDS="$MOD_IDS $mod_id"
                ;;
        esac
    done
    # 检查存档MOD配置文件是否存在
    if [ -f "$KLEI_DIR/$CLUSTER/Master/modoverrides.lua" ]; then
        # 如果世界MOD文件存在,则复制到脚本目录中一份
        cp $KLEI_DIR/$CLUSTER/Master/modoverrides.lua $SCRIPT_DIR/world_set/modoverrides_bak.lua
        # 删除最后的空格
        sed -i '/^$/d' $SCRIPT_DIR/world_set/modoverrides_bak.lua
        # 删除最后一行
        sed -i '$d' $SCRIPT_DIR/world_set/modoverrides_bak.lua
        # 在最后一行添加逗号
        sed -i '$s/$/,/' $SCRIPT_DIR/world_set/modoverrides_bak.lua; else
            if [ -f "$SCRIPT_DIR/world_set/modoverrides_bak.lua" ]; then
                rm $SCRIPT_DIR/world_set/modoverrides_bak.lua
            fi
        echo "return {" >> $SCRIPT_DIR/world_set/modoverrides_bak.lua
        # 添加默认MOD
        MOD_IDS="$MOD_IDS $DEFAULT_MOD_A"
    fi
    # 写入文件
    for i in $MOD_IDS; do
        echo "ServerModSetup(\"$i\")" >> $DST_DIR/mods/dedicated_server_mods_setup.lua
        echo "  [\"workshop-$i\"]={ configuration_options={  }, enabled=true }," >> $SCRIPT_DIR/world_set/modoverrides_bak.lua
    done
    # 删除最后结尾处的逗号,并添加 }
    sed -i '/^$/d' $SCRIPT_DIR/world_set/modoverrides_bak.lua
    sed -i '$s/,$//' $SCRIPT_DIR/world_set/modoverrides_bak.lua
    echo "}" >> $SCRIPT_DIR/world_set/modoverrides_bak.lua
    # 到此生成MOD配置文件完毕
    cp $SCRIPT_DIR/world_set/modoverrides_bak.lua $KLEI_DIR/$CLUSTER/Master/modoverrides.lua
    cp $SCRIPT_DIR/world_set/modoverrides_bak.lua $KLEI_DIR/$CLUSTER/Caves/modoverrides.lua
}

function world_set() {
    print_log "是否使用默认设置?"
    read -p " (default: y)[y/n]:" key

    case $key in
        'n')
            read -p " 世界名称:" world_name
                print_log ""
                read -p " 世界描述(可为空):" world_des
            print_log ""
                read -p " 世界密码(可为空):" world_pass
                print_log ""
                read -p " 用户token:" user_token
            ;;
        *)
            print_log "写入默认配置..."
            world_name="拉比拉比镇的小兔子的世界"
            world_des="默认设置,长时间没人会重置时间.如有问题请联系服主QQ:782777216"       
            world_pass=""
            user_token="pds-g^KU_uGVY9tdU^MA7CyDfP39QoRCHJcYJKAtZrpQsy8gQSdsg50g4A6jg="
            ;;
    esac

    print_log "世界名称:$world_name\n 世界描述:$world_des\n 世界密码:$world_pass\n 用户token:$user_token\n" "azure"
    read -p " 确认[y/n]:" key

    case $key in
        'n')
            print_log "重新设置!" "red"
            world_set
            ;;
        *)
            ;;
    esac
}

function create_file() {
    mkdir -p $KLEI_DIR/$CLUSTER
    mkdir -p $KLEI_DIR/$CLUSTER/Master
    mkdir -p $KLEI_DIR/$CLUSTER/Caves

    world_set

    print_log ""
    read -p " 是否添加管理员(用户token所有者默认拥有管理权限)[y/n]:" key
    print_log ""

    case $key in
        'y')
            rm -rf $SCRIPT_DIR/world_set/adminlist_bak.txt
            while (true); do
                read -p " 输入管理员ID(输入ok结束):" w_admin
                print_log ""
                if [ "$w_admin" == "ok" ]; then
                    break
                fi
                echo "$w_admin" >> $SCRIPT_DIR/world_set/adminlist_bak.txt
            done

            for i in ${DEFAULT_ADMIN_A[@]};do
                echo "$i" >> $SCRIPT_DIR/world_set/adminlist_bak.txt
            done
            cp $SCRIPT_DIR/world_set/adminlist_bak.txt $KLEI_DIR/$CLUSTER/adminlist.txt
            ;;
        *)
            ;;
    esac

    declare -A CLUSTER_INI=(["game_mode"]="endless" ["max_players"]="6" ["pvp"]="false" ["pause_when_empty"]="true"
        ["lan_only_cluster"]="false" ["cluster_intention"]="cooperative" ["cluster_password"]="$world_pass"
        ["cluster_description"]="$world_des" ["cluster_name"]="$world_name" ["offline_cluster"]="false"
        ["cluster_language"]="zh" ["console_enabled"]="true" ["shard_enabled"]="true" ["bind_ip"]="127.0.0.1"
        ["master_ip"]="127.0.0.1" ["master_port"]="10888" ["cluster_key"]="defaultPass")

    declare -A SERVER_INI_MASTER=(["server_port"]="10999" ["is_master"]="true" ["encode_user_path"]="true")

    declare -A SERVER_INI_CAVES=(["server_port"]="10998" ["is_master"]="false" ["encode_user_path"]="true"
        ["name"]="Caves" ["id"]="1931143336" ["master_server_port"]="27017" ["authentication_port"]="8767")

    rm -f $SCRIPT_DIR/world_set/cluster_bak.ini
    rm -f  $SCRIPT_DIR/world_set/server_master_bak.ini
    rm -f $SCRIPT_DIR/world_set/server_caves_bak.ini

    for i in ${CLUSTER_INI_A[@]}; do
        case $i in 
            'game_mode')
                echo -e "[GAMEPLAY]" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                echo "$i = ${CLUSTER_INI[$i]}" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                ;;
            'lan_only_cluster')
                echo -e "\n\n[NETWORK]" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                echo "$i = ${CLUSTER_INI[$i]}" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                ;;
            'console_enabled')
                echo -e "\n\n[MISC]" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                echo "$i = ${CLUSTER_INI[$i]}" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                ;;
            'shard_enabled')
                echo -e "\n\n[SHARD]" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                echo "$i = ${CLUSTER_INI[$i]}" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                ;;
            *)
                echo "$i = ${CLUSTER_INI[$i]}" >> $SCRIPT_DIR/world_set/cluster_bak.ini
                ;;
        esac
    done

    for i in ${SERVER_INI_MASTER_A[@]}; do
        case $i in
            'server_port')
                echo -e "[NETWORK]" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                echo "$i = ${SERVER_INI_MASTER[$i]}" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                ;;
            'is_master')
                echo -e "\n\n[SHARD]" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                echo "$i = ${SERVER_INI_MASTER[$i]}" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                ;;
            'encode_user_path')
                echo -e "\n\n[ACCOUNT]" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                echo "$i = ${SERVER_INI_MASTER[$i]}" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                ;;
            *)
                echo "$i = ${SERVER_INI_MASTER[$i]}" >> $SCRIPT_DIR/world_set/server_master_bak.ini
                ;;
        esac
    done

    for i in ${SERVER_INI_CAVES_A[@]}; do
        case $i in
            'server_port')
                echo -e "[NETWORK]" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                echo "$i = ${SERVER_INI_CAVES[$i]}" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                ;;
            'is_master')
                echo -e "\n\n[SHARD]" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                echo "$i = ${SERVER_INI_CAVES[$i]}" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                ;;
            'encode_user_path')
                echo -e "[\n\nACCOUNT]" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                echo "$i = ${SERVER_INI_CAVES[$i]}" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                ;;
            'master_server_port')
                echo -e "\n\n[STEAM]" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                echo "$i = ${SERVER_INI_CAVES[$i]}" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                ;;
            *)
            echo "$i = ${SERVER_INI_CAVES[$i]}" >> $SCRIPT_DIR/world_set/server_caves_bak.ini
                ;;
        esac
    done

    cp $SCRIPT_DIR/world_set/cluster_bak.ini $KLEI_DIR/$CLUSTER/cluster.ini
    cp $SCRIPT_DIR/world_set/server_master_bak.ini $KLEI_DIR/$CLUSTER/Master/server.ini
    cp $SCRIPT_DIR/world_set/server_caves_bak.ini $KLEI_DIR/$CLUSTER/Caves/server.ini
    cp NULLleveldataoverride_master.lua $KLEI_DIR/$CLUSTER/Master/leveldataoverride.lua
    cp NULLleveldataoverride_caves.lua $KLEI_DIR/$CLUSTER/Caves/leveldataoverride.lua
    echo "$user_token" >> $KLEI_DIR/$CLUSTER/cluster_token.txt
}

function check_file() {
    print_log "是否强制重建存档?" "red"
    print_log ""
    read -p " 之前存档会丢失!!![y/n]:" key
    case $key in 
        'y')
            print_log "正在删除存档..." "green"
            if [ -d "$KLEI_DIR/$CLUSTER" ]; then
                rm -rf $KLEI_DIR/$CLUSTER
            fi
            create_file
            ;;
        *)
            print_log "正在检查存档..." "yellow"
            if [ ! -d "$KLEI_DIR/$CLUSTER" ]; then
                print_log "默认存档不存在,正在创建..." "red"
                create_file; else
                list="$KLEI_DIR/$CLUSTER/Master/leveldataoverride.lua $KLEI_DIR/$CLUSTER/Master/server.ini $KLEI_DIR/$CLUSTER/cluster.ini"
                for i in $list; do
                    if [ ! -f "$i" ]; then
                        print_log "存档文件有缺失,重新创建..." "red"
                        rm -rf $KLEI_DIR/$CLUSTER
                        create_file
                        break
                    fi
                done
            fi
            ;;
    esac
}

function start_game() {
    print_log "请选择:\n 1.正式服\n 2.测试服(Return of Them Public Beta)\n" "azure"
    read -p " (默认为正式服):" key
    case $key in
        '2')
            print_log "当前选择为测试服..." "green"
            DST_DIR="NULL/dst_beta"
            UPDATE_PARAM="-beta returnofthembeta"
            KLEI_DIR="NULL/.klei/DoNotStarveTogetherReturnOfThemBeta"
            DOC_FILE="$SCRIPT_DIR/world_set/beta_"
            ;;
        *)
            print_log "当前选择为正式服..." "green"
            DST_DIR="NULL/dst"
            UPDATE_PARAM="validate"
            KLEI_DIR="NULL/.klei/DoNotStarveTogether"
            DOC_FILE="$SCRIPT_DIR/world_set/"
            ;;
    esac

    check_file

    read -p " 是否添加MOD(默认为否)[y/n]:" key
    case $key in
        'y')
            add_mods
            ;;
        *)
            # do nothing
            ;;
    esac

    print_log ""
    read -p " 是否下载或更新游戏与MOD(更新完成后会直接启动游戏)[y/n]:" key
    case $key in
        'y')
            update
            ;;
        *)
            ;;
    esac

    print_log "启动游戏" "green"

    if [ -z NULL ]; then
        DST_DIR="NULL/dst"
    fi

    # 此处启动饥荒服务器时必须进入饥荒服务器文件夹中的bin目录中,否则无法会报无法切换至../data文件的错误
    cd $DST_DIR/bin
    screen -dmS "dst_overworld" ./dontstarve_dedicated_server_nullrenderer -console -cluster $CLUSTER -shard Master
    screen -dmS "dst_caves" ./dontstarve_dedicated_server_nullrenderer -console -cluster $CLUSTER -shard Caves
}

function kill_pid() {
    print_log "强制重启游戏中..." "red"
    for i in $PID
    do
        kill -9 $i
    done
    screen -wipe > /dev/null 2>&1
    start_game
}

function check() {
    if [ -z "$PID" ]; then
        start_game; else
        print_log "游戏已启动!!!\n" "red"
        read -p " 是否强制重启[y/n](存档可能会损坏!!!):" key
        case $key in
            'y')
                kill_pid
                ;;
            *)
                ;;
        esac
    fi
}

function main() {
    check
}

main

拉取数据并插入数据库

#!/bin/bash

LAST_MONTH_DATE=`date -d "1 month ago" "+%Y-%m"`
SCHEMA="xxx_xx"
TABLE="xx_xxx"
FIELDS="phone_number"
SRC_FILE_PATH="/mnt/xxx/xxx_xxx/NULL_xx.txt"
DES_FILE_PATH="NULL/xxx_xxx/NULL_xx.txt"

function print_log() {
    echo -e `date "+%Y-%m-%d %H:%M:%S"` : $1
}

function commit() {
    psql -d postgres -h 132.xx.xxx.30 -p 5xxx -U user_xx -c "$1"
}

function get_file() {
    print_log "拉取文件"

    if [ -f $SRC_FILE_PATH ]; then
        cp $SRC_FILE_PATH $DES_FILE_PATH
        return 0; else
        return 1
    fi
}

function check() {
    result_lines=`commit "select count(1) from $SCHEMA.$TABLE" | sed -n '3p' | sed s/[[:space:]]//g`

    if [ $result_lines -eq $src_lines ];then
        return 0; else
        return 1
    fi
}

function main() {
    print_log "开始..."

    if ( get_file ); then
        print_log "数据拉取成功"

        src_lines=`wc -l $DES_FILE_PATH | awk '{print $1}'`

        print_log "准备清空数据表NULL.NULL"
        commit "truncate NULL.NULL" > /dev/null 2>&1
        print_log "准备插入数据"
        commit "\copy NULL.NULL (NULL) from 'NULL' delimiter ','"

        if ( check ); then
            print_log "数据插入成功,共 NULL 条数据..."; else
            print_log "数据未完全插入,请检查!"
        fi; else

        print_log "数据拉取失败"
    fi
}

main

拼接SQL并执行(由于SQL过长,直接使用命令会报错,因此放入文件中执行):

#!/bin/bash

SQL=""
TMP_SQL=""
SQL1="start_date,"
SQL2="start_date,"
SQL3="a.start_date,"
SCHEMA1="unicom_tmp_schema"
SCHEMA2="unicom_2i_hold_schema"
TABLE1="tb_fullstop_activity_user_trace_tmp"
TABLE2="tb_user_state"
TABLE3="tb_user_state_history"
TERMS=("= '0'" "= '5'" "= ''" "in ('A','B')" "not in ('0','5','A','B','')")
SCRIPT_DIR=$(cd `dirname $0`;pwd)
FILE_PATH="NULL/tmp_fullstop.sql"
DES_PATH="NULL/daily_th/fullstop_activity"

function print_log() {
    echo -e `date "+%Y-%m-%d %H:%M:%S"` : $1
}

function commit() {
    # 新库
    psql -d postgres -h ***.***.***.** -p *** -U *** -c "$1 "
}

function commit_file() {
    psql -d postgres -h ***.***.***.** -p *** -U *** -f NULL
}

function replace_tag() {
    print_log "替换占位符"
    print_log "当前条件为:[ NULL ]"
    print_log "文件存储位置:[ NULL/NULL.csv ]"

    TMP_SQL=${SQL//\?/NULL}

    echo ${TMP_SQL//@/NULL} >> NULL

    print_log "占位符替换完毕.准备执行SQL"
}
function fix_sql() {
    print_log "整理需要执行的SQL语句"

    i=1
    delimit=","
    while [ 1 ]; do
        let j=i+1
        SQL1=NULL"sum(s_NULL)NULL"
        SQL2=NULL"sum(c_NULL) as s_NULLNULL"
        SQL3=NULL"case when split_part(b.stateset,'|',a.start_date - b.stat_date + $j) ? then 1 else 0 end as c_NULLNULL"
        if [ $i -eq 9 ]; then
            break; elif [ $i -eq 8 ]; then
            delimit=""
            let i++; else
            let i++
        fi
    done

    SQL="\copy (
        select NULL from(
        select NULL from (select NULL from NULL.NULL a left join NULL.NULL b 
        on a.phone_number = b.phone_number where b.stateset is not null and a.start_date - b.stat_date + 2 > 0) t1
        group by start_date
        union all
        select NULL from (select NULL from NULL.NULL a left join NULL.NULL b
        on a.phone_number = b.phone_number where b.stateset is not null and a.start_date - b.stat_date + 2 > 0) t2
        group by start_date) t group by start_date order by start_date
    ) to NULL/@.csv delimiter ','"

    print_log "SQL语句整理完毕"
}

function main() {
    print_log "开始..."

    fix_sql

    for i in `seq 0 $((${#TERMS[*]} - 1))`; do
        replace_tag "NULL" "${TERMS[NULL]}"
        commit_file NULL
        print_log "执行完毕.删除临时文件"
        rm NULL
    done

    print_log "成功"
}

main

时至今日,你依旧是我的光芒。