
Description:
Quickly lookup any player’s Username, EOSID and First & Last time seen
as well as automatically copy the full EOSID to Clipboard (when run locally)
Can search using Partial Playername OR Partial EOSID
Furthermore, provides capability to lookup a Player’s Tribe ID’s
across the entire cluster.
Commands:
idlookup <player> ──── Search the database for a user’s EOSID
idlookup -t <player> ──── Search the database for a user’s TribeID
idlookup -b ──── Build EOSID database from ALL available logs
idlookup -bt ──── Build Tribe database from ALL available logs
Examples:
idlookup wolf
idlookup -t wolf
#!/bin/bash
#
#
set -e
####################
# CONFIGURATION
####################
# DESIRED LOCAL DB PATHS
EOSID_DIR="/c/ark/eosid/"
DB_FILE="${EOSID_DIR}eosdb.csv"
TRIBE_DB="${EOSID_DIR}tribedb.csv"
EOSID_SCRAPED="${EOSID_DIR}eosid_scraped_logs.txt"
TRIBE_SCRAPED="${EOSID_DIR}tribe_scraped_logs.txt"
# LOCAL CLIPBOARD
CLIPBOARD="clip.exe"
# ARK SERVERS
#
# Format:
# "Map Name|Server Root Path"
#
SERVERS=(
"Island|/C/ARK/Island"
"Ragnarok|/C/ARK/Ragnarok"
"Aberration|/C/ARK/Aberration"
"Extinction|/C/ARK/Extinction"
"Astraeos|/C/ARK/Astraeos"
"Genesis|/C/ARK/Genesis"
)
####################
# END CONFIGURATION
####################
VERSION="EOSID Lookup v4.2.2"
####################
# DATA ARRAYS
####################
shopt -s nullglob
ALL_LOGS=()
for server in "${SERVERS[@]}"; do
path="${server#*|}"
ALL_LOGS+=("$path/ShooterGame/Saved/Logs/"*.log)
done
shopt -u nullglob
declare -A DB_SteamName
declare -A DB_SurvivorName
declare -A DB_FirstSeen
declare -A DB_LastSeen
declare -A DB_TimesSeen
####################
# COLOUR VARIABLES
####################
# Terminal Formatting
RESET="\033[0m"
BOLD="\033[1m"
# UI Colours
CLR_RED="\033[38;5;196m" # Bright Red
CLR_GREEN="\033[38;5;46m" # Bright Lime Green
CLR_GOLD="\033[38;5;226m" # Gold
CLR_PURPLE="\033[38;5;141m" # Light Purple / Lavender
CLR_BLUE="\033[38;5;4m" # Bright Sky Blue
CLR_DGREEN="\033[38;5;2m" # Dark Forest Green
CLR_ORANGE="\033[38;5;208m" # Orange
CLR_AQUA="\033[38;5;51m" # Aqua
CLR_PINK="\033[38;5;199m" # PINK
CLR_PAQUA="\033[38;5;195m" # Pale Aqua
CLR_TEXT="\033[38;5;252m" # Light Grey
CLR_TITLE="\033[38;5;147m" # Pale Blue
CLR_SAVE="\033[38;5;245m" # Darker Grey
####################
# FUNCTIONS
####################
usage() {
echo
echo -e "${CLR_TITLE}${BOLD}${VERSION}${RESET}"
echo
echo -e "${BOLD}Description:${RESET}${CLR_TEXT}"
echo -e " Quickly lookup any player's Username, EOSID and First & Last time seen"
echo -e " as well as automatically copy the full EOSID to Clipboard"
echo -e " Can search using Partial Playername OR Partial EOSID"
echo -e " Furthermore, provides capability to lookup a Player's Tribe IDs across the entire cluster.${RESET}"
echo
echo -e "${BOLD}Usage:${RESET}${CLR_TEXT}"
echo -e " idlookup <Player> ──── Search the database for a user's EOSID "
echo -e " idlookup -t <Player> ──── Search the database for a user's TribeID "
echo
echo -e " idlookup -b ──── Build EOSID database from ALL available logs "
echo -e " idlookup -bt ──── Build Tribe database from ALL available logs${RESET}"
echo
echo -e "${BOLD}Examples:${RESET}${CLR_TEXT}"
echo -e " idlookup wolf"
echo -e " idlookup -t wolf${RESET}"
echo
exit 1
}
#
# EOSID BUILD
#
cmd_build() {
if [[ ! -f "$EOSID_SCRAPED" ]]; then
echo
echo -e "${CLR_GOLD}${BOLD}Building EOSID Database...${RESET}"
echo " Depending on the quantity of your archived logs, the first scan may take several minutes..."
echo
echo " ${BOLD}Be Advised:${RESET} Once this first scan has completed, only new logs will be scanned in the future"
echo " this will ${BOLD}dramatically${RESET} reduce the processing time moving forward - from minutes to seconds."
else
echo -e "${CLR_GOLD}${BOLD} ▶ Scanning new logs & appending the EOSID Database...${RESET}"
fi
#
# Load existing EOSID database
#
if [[ -f "$DB_FILE" ]]; then
while IFS=',' read -r eosid steam survivor firstseen lastseen timesseen; do
[[ "$eosid" == "EOSID" ]] && continue
DB_SteamName["$eosid"]="$steam"
DB_SurvivorName["$eosid"]="$survivor"
DB_FirstSeen["$eosid"]="$firstseen"
DB_LastSeen["$eosid"]="$lastseen"
DB_TimesSeen["$eosid"]="$timesseen"
done <"$DB_FILE"
fi
# cross-reference the all_logs array with the scaped_logs.txt - remove already scanned logs and add leftovers to
# a new array NEW_LOGS
touch "$EOSID_SCRAPED"
declare -A SCRAPED_LOGS
while IFS= read -r log; do
SCRAPED_LOGS["$log"]=1
done <"$EOSID_SCRAPED"
NEW_LOGS=()
for log in "${ALL_LOGS[@]}"; do
if [[ -z ${SCRAPED_LOGS["$log"]+x} ]]; then
NEW_LOGS+=("$log")
fi
done
echo
echo "───────────────────────────"
echo "Total logs found: ${#ALL_LOGS[@]}"
echo "New logs to scan: ${#NEW_LOGS[@]}"
echo "───────────────────────────"
if [[ ${#NEW_LOGS[@]} -eq 0 ]]; then
echo
echo "No new logs to process."
echo -e "${CLR_GREEN}All up to date!${RESET}"
return
fi
#
# PASS 1 - SteamName -> EOSID
#
while IFS= read -r line; do
if [[ $line =~ ([0-9]{4}\.[0-9]{2}\.[0-9]{2}_[0-9]{2}\.[0-9]{2}\.[0-9]{2}):[[:space:]](.+)[[:space:]]\[UniqueNetId:([[:xdigit:]]+) ]]; then
timestamp="${BASH_REMATCH[1]}"
player="${BASH_REMATCH[2]}"
eosid="${BASH_REMATCH[3]}"
DB_SteamName["$eosid"]="$player"
if [[ -z ${DB_FirstSeen[$eosid]} || "$timestamp" < "${DB_FirstSeen[$eosid]}" ]]; then
DB_FirstSeen["$eosid"]="$timestamp"
fi
if [[ -z ${DB_LastSeen[$eosid]} || "$timestamp" > "${DB_LastSeen[$eosid]}" ]]; then
DB_LastSeen["$eosid"]="$timestamp"
fi
((++DB_TimesSeen["$eosid"]))
fi
done < <(
grep -hEi "joined this ARK|left this ARK" "${NEW_LOGS[@]}"
)
#
# PASS 2 - Survivor -> EOSID
#
local LastSurvivor=""
while IFS= read -r line; do
if [[ $line =~ :[[:space:]]([^:]+)[[:space:]]froze[[:space:]] ]]; then
LastSurvivor="${BASH_REMATCH[1]}"
continue
fi
if [[ $line =~ Frozen[[:space:]]by[[:space:]]ID:[[:space:]]([[:xdigit:]]+) ]]; then
eosid="${BASH_REMATCH[1]}"
if [[ -n "$LastSurvivor" ]]; then
DB_SurvivorName["$eosid"]="$LastSurvivor"
fi
LastSurvivor=""
fi
done < <(
grep -hEi "froze |Frozen by ID:" "${NEW_LOGS[@]}"
)
#
# PASS 3 - Historical chat fallback
#
while IFS= read -r line; do
if [[ $line =~ :[[:space:]](.+)[[:space:]]\(([^()]+)\):[[:space:]] ]]; then
player="${BASH_REMATCH[1]}"
survivor="${BASH_REMATCH[2]}"
for eosid in "${!DB_SteamName[@]}"; do
if [[ "${DB_SteamName[$eosid]}" == "$player" && -z "${DB_SurvivorName[$eosid]}" ]]; then
DB_SurvivorName["$eosid"]="$survivor"
break
fi
done
fi
done < <(
grep -hE " \([^()]+\): " "${NEW_LOGS[@]}"
)
# Record logs that have been scraped
for log in "${NEW_LOGS[@]}"; do
if ! grep -Fxq "$log" "${EOSID_SCRAPED}"; then
echo "$log" >>"${EOSID_SCRAPED}"
fi
done
echo
echo "────────────────────────────────────"
echo -e "${CLR_GREEN} ▶ Finished Building EOSID Database!${RESET}"
echo "────────────────────────────────────"
cmd_export
}
cmd_export() {
{
echo "EOSID,SteamName,SurvivorName,FirstSeen,LastSeen,TimesSeen"
for eosid in "${!DB_SteamName[@]}"; do
echo "$eosid,${DB_SteamName[$eosid]},${DB_SurvivorName[$eosid]},${DB_FirstSeen[$eosid]},${DB_LastSeen[$eosid]},${DB_TimesSeen[$eosid]}"
done
} >"$DB_FILE"
}
#
# TRIBE
#
cmd_tribebuild() {
if [[ ! -f "$TRIBE_SCRAPED" ]]; then
echo
echo -e "${CLR_GOLD}${BOLD}Building Tribe Database...${RESET}"
echo " Depending on the quantity of your archived logs, the first scan may take several minutes..."
echo
echo " ${BOLD}Be Advised:${RESET} Once this first scan has completed, only new logs will be scanned in the future"
echo " this will ${BOLD}dramatically${RESET} reduce the processing time moving forward - from minutes to seconds."
else
echo -e "${CLR_GOLD}${BOLD} ▶ Scanning new logs & appending the Tribe Database...${RESET}"
fi
# cross-reference the all_logs array with the scaped_logs.txt - remove already scanned logs and add leftovers to
# a new array NEW_LOGS
touch "$TRIBE_SCRAPED"
declare -A SCRAPED_LOGS
while IFS= read -r log; do
SCRAPED_LOGS["$log"]=1
done <"$TRIBE_SCRAPED"
NEW_LOGS=()
for log in "${ALL_LOGS[@]}"; do
if [[ -z ${SCRAPED_LOGS["$log"]+x} ]]; then
NEW_LOGS+=("$log")
fi
done
echo
echo "───────────────────────────"
echo "Total logs found: ${#ALL_LOGS[@]}"
echo "New logs to scan: ${#NEW_LOGS[@]}"
echo "───────────────────────────"
if [[ ${#NEW_LOGS[@]} -eq 0 ]]; then
echo
echo "No new logs to process"
echo -e "${CLR_GREEN}All up to date!${RESET}"
return
fi
declare -A TribeRecords
declare -A JoinRecords
#
# Load existing Tribe database
#
if [[ -f "$TRIBE_DB" ]]; then
while IFS=',' read -r map player playerid tribe tribeid; do
[[ "$map" == "Map" ]] && continue
key="$map|$player"
TribeRecords["$key"]="$map,$player,$playerid,$tribe,$tribeid"
if [[ "$playerid" != "Unknown" ]]; then
JoinRecords["$key"]=1
fi
done <"$TRIBE_DB"
fi
#
# PASS 1: Authoritative "joined tribe" records
#
while IFS= read -r line; do
map=""
for server in "${SERVERS[@]}"; do
server_map="${server%%|*}"
server_path="${server#*|}"
if [[ "$line" == *"$server_path"* ]]; then
map="$server_map"
break
fi
done
[[ -n "$map" ]] || continue
joinline="${line%% Invited by Player *}"
if [[ $joinline =~ Player[[:space:]](.+)[[:space:]]with[[:space:]]ID[[:space:]]([0-9]+)[[:space:]]joined[[:space:]]tribe[[:space:]](.+)[[:space:]]with[[:space:]]ID[[:space:]]([0-9]+)\. ]]; then
player="${BASH_REMATCH[1]}"
playerid="${BASH_REMATCH[2]}"
tribe="${BASH_REMATCH[3]}"
tribeid="${BASH_REMATCH[4]}"
key="$map|$player"
TribeRecords[$key]="$map,$player,$playerid,$tribe,$tribeid"
JoinRecords[$key]=1
fi
done < <(grep -HE "joined tribe .* with ID [0-9]+" "${NEW_LOGS[@]}")
#
# PASS 2: Cryopod fallback
#
declare -A TribeLastSeen=()
while IFS= read -r line; do
map=""
for server in "${SERVERS[@]}"; do
server_map="${server%%|*}"
server_path="${server#*|}"
if [[ "$line" == *"$server_path"* ]]; then
map="$server_map"
break
fi
done
[[ -n "$map" ]] || continue
if [[ $line =~ \[([0-9]{4}\.[0-9]{2}\.[0-9]{2}-[0-9]{2}\.[0-9]{2}\.[0-9]{2}):[0-9]+\].*Tribe[[:space:]](.+),[[:space:]]ID[[:space:]]([0-9]+):.*:[[:space:]]([^:]+)[[:space:]]froze[[:space:]] ]]; then
timestamp="${BASH_REMATCH[1]}"
tribe="${BASH_REMATCH[2]}"
tribeid="${BASH_REMATCH[3]}"
player="${BASH_REMATCH[4]}"
key="$map|$player"
# Only accept the newest cryopod event for this player.
if [[ -z ${TribeLastSeen[$key]:-} || "$timestamp" > "${TribeLastSeen[$key]}" ]]; then
TribeLastSeen["$key"]="$timestamp"
# Preserve authoritative PlayerID when we already have one.
if [[ -n ${TribeRecords[$key]:-} ]]; then
IFS=',' read -r old_map old_player old_playerid old_tribe old_tribeid <<< "${TribeRecords[$key]}"
TribeRecords[$key]="$map,$player,$old_playerid,$tribe,$tribeid"
else
TribeRecords[$key]="$map,$player,Unknown,$tribe,$tribeid"
fi
fi
fi
done < <(
grep -HE "Tribe .* ID [0-9]+:.* froze " "${NEW_LOGS[@]}"
)
#
# Record logs that have been scraped
#
for log in "${NEW_LOGS[@]}"; do
if ! grep -Fxq "$log" "$TRIBE_SCRAPED"; then
echo "$log" >>"$TRIBE_SCRAPED"
fi
done
#
# Export
#
{
echo "Map,Player,PlayerID,TribeName,TribeID"
for key in "${!TribeRecords[@]}"; do
echo "${TribeRecords[$key]}"
done | sort
} >"$TRIBE_DB"
echo
echo "────────────────────────────────────"
echo -e "${CLR_GREEN} ▶ Finished Building Tribes Database!${RESET}"
echo "────────────────────────────────────"
}
#
# SEARCHING
#
cmd_search() {
local query="$1"
local found=0
if [[ ! -f "$DB_FILE" ]]; then
echo
echo -e "${CLR_RED}${BOLD} Error:${RESET} EOSID database does not exist:${CLR_TEXT} ${DB_FILE} ${RESET}"
echo
echo -e " ▶ Run ${BOLD}idlookup -b${RESET} to scan logfiles and poopulate the database"
echo
exit 1
fi
echo
echo "────────────────────────────────────────────────"
while IFS=',' read -r eosid steam survivor firstseen lastseen timesseen; do
# Skip the CSV header
[[ $eosid == "EOSID" ]] && continue
shopt -s nocasematch
if [[ $eosid == *"$query"* || $steam == *"$query"* || $survivor == *"$query"* ]]; then
printf "%s" "$eosid" | $CLIPBOARD
echo -e " ${BOLD}Steam${RESET} : $steam"
echo -e " ${BOLD}Survivor${RESET} : $survivor"
echo -e " ${BOLD}EOSID${RESET} : $eosid"
echo
echo -e " ${BOLD}First Seen${RESET} : $firstseen"
echo -e " ${BOLD}Last Seen${RESET} : $lastseen"
echo -e " ${BOLD}Times Seen${RESET} : $timesseen"
echo "────────────────────────────────────────────────"
found=1
fi
shopt -u nocasematch
done <"$DB_FILE"
if [[ $found -eq 0 ]]; then
echo "No matches found."
else
echo
echo -e " ${CLR_GOLD}▶ EOSID copied to clipboard.${RESET}"
fi
echo
}
cmd_tribesearch() {
local query="$1"
local player=""
local playerid=""
local steam=""
local survivor=""
# Try to resolve query via EOS database
if [[ -f "$DB_FILE" ]]; then
# First: look for an exact Steam/Survivor/EOSID match
while IFS=',' read -r eosid db_steam db_survivor firstseen lastseen timesseen; do
[[ "$eosid" == "EOSID" ]] && continue
shopt -s nocasematch
if [[ "$db_steam" == "$query" || "$db_survivor" == "$query" || "$eosid" == "$query" ]]; then
steam="$db_steam"
survivor="$db_survivor"
break
fi
shopt -u nocasematch
done < "$DB_FILE"
# If no exact match, fall back to partial matching
if [[ -z "$steam" ]]; then
while IFS=',' read -r eosid db_steam db_survivor firstseen lastseen timesseen; do
[[ "$eosid" == "EOSID" ]] && continue
shopt -s nocasematch
if [[ "$db_survivor" == *"$query"* || "$db_steam" == *"$query"* || "$eosid" == *"$query"* ]]; then
steam="$db_steam"
survivor="$db_survivor"
break
fi
shopt -u nocasematch
done < "$DB_FILE"
fi
fi
if [[ ! -f "$TRIBE_DB" ]]; then
echo
echo -e "${CLR_RED}${BOLD} Error:${RESET} Tribe database does not exist:${CLR_TEXT} ${TRIBE_DB} ${RESET}"
echo
echo -e " ▶ Run ${BOLD}idlookup -bt${RESET} to scan logfiles and poopulate the Tribes database"
echo
exit 1
fi
#
# If EOS lookup found a player, use their Steam name.
# Otherwise use the original query.
#
[[ -n "$steam" ]] || steam="$query"
#
# Find matching player in Tribe DB
#
while IFS=',' read -r map db_player db_playerid db_tribe tribeid; do
[[ "$map" == "Map" ]] && continue
shopt -s nocasematch
if [[ "$db_player" == "$steam" ]]; then
player="$db_player"
playerid="$db_playerid"
break
fi
shopt -u nocasematch
done <"$TRIBE_DB"
shopt -u nocasematch
if [[ -z "$player" ]]; then
echo
echo "No player matches found."
echo
return
fi
#
# Display player
#
echo
echo "──────────────────────────────"
echo -e "${CLR_GOLD}Steam ${RESET}: $steam"
echo -e "${CLR_GOLD}Survivor ${RESET}: $survivor"
echo -e "${CLR_GOLD}Player ID ${RESET}: $playerid"
echo "──────────────────────────────"
echo -e "${CLR_AQUA}Tribe: ${RESET}"
#
# Display every map's tribe + tribe ID
#
while IFS=',' read -r map db_player db_playerid db_tribe tribeid; do
[[ "$map" == "Map" ]] && continue
if [[ "$db_player" == "$player" ]]; then
printf " %-12s : %-18s : %s\n" "$map" "$db_tribe" "$tribeid"
fi
done <"$TRIBE_DB"
echo "──────────────────────────────"
}
####################
# COMMANDS
####################
case "${1:-}" in
-b)
cmd_build
;;
-bt)
cmd_tribebuild
;;
-t)
[[ -n ${2:-} ]] || usage
cmd_tribesearch "$2"
;;
"")
usage
;;
-*)
usage
;;
*)
cmd_search "$1"
;;
esac
