You are not logged in.

#1 2019-06-15 22:45:12

7thCore
Member
Registered: 2018-06-09
Posts: 65

[SOLVED] Bash script to wait and listen for a string in a screen

I have a bash script to save, sync and backup files for a program running in a custom tmpfs/ramdisk mounted dir.

The program in question is running in a screen session and also has logging enabled.

A save command is issued by the script to the screen session every 15 minutes and after that rsync syncs the files to hdd.

The problem is that the script issues the save command and immediately start rsync after that so the program dosen't have a chance to save all the files and the result is a corrupt save on the hdd.

I'm thinking of making a while loop to wait for a matching string in the screen log file or maybe in the screen itself if possible. Another problem is there are multiple matching strings from previous save commands so the script should only listen for new lines generated from the time the command runs till the new string pops up.

The string it should be waiting for is:

[Server]: Save completed.

However I don't have the experience nor the knowledge to get this working. I did a lot of digging around the internet, trying various commands in a vm (better safe than sorry) and nothing worked properly.

One of the thing I tried was:

tail -f screen.0 | grep -m 1 '[Server]: Save completed.'

I know that i coukd use the sleep command to some extent but the program takes sometimes a few seconds, sometimes a few minutes to save.

Does anyone know how I should go about this?

Last edited by 7thCore (2019-06-17 14:25:43)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#2 2019-06-15 23:24:51

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Run sync after the (successful) exit status of rsync.


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#3 2019-06-16 03:28:42

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

jasonwryan wrote:

Run sync after the (successful) exit status of rsync.

Here is no sync. There is only the save command that gets passed to the screen and rsync.


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#4 2019-06-16 03:38:38

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 30,424
Website

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Whatever: same principle... test the exit status and then either bail or run the next command.

In any event, paste the actual script rather than assuming that everyone knows what it is doing.


Arch + dwm   •   Mercurial repos  •   Surfraw

Registered Linux User #482438

Offline

#5 2019-06-16 10:26:33

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Alright. Here is the entire script:

 
#!/bin/bash

#Interstellar Rift server script by 7thCore
#Leave this variable alone, it is tied in with the systemd service file so it changes accordingly by it.
SCRIPT_ENABLED="1"

#Basics
NAME="IsRSrv" #Name of the screen
USER="$(whoami)" #Get user's username

#Steamcmd login
STEAMCMDUID="user" #Your steam username
STEAMCMDPSW="pass" #Your steam password
APPID="363360" #app id of the steam game

#Server configuration
SERVICE_NAME="isrsrv" #Name of the service files, script and script log
SRV_DIR_NAME="interstellar_rift" #Main directory name
SRV_DIR="/home/$USER/servers/$SRV_DIR_NAME/server" #Location of the server located on your hdd/ssd
SCRIPT_NAME="$SERVICE_NAME-script.bash" #Script name
SCRIPT_DIR="/home/$USER/servers/$SRV_DIR_NAME/scripts" #Location of this script
SCRIPT_LOG="$SCRIPT_DIR/$SERVICE_NAME-script.log" #Script log
UPDATE_DIR="/home/$USER/servers/$SRV_DIR_NAME/updates" #Location of update information for the script's automatic update feature

#Wine configuration
WINE_ARCH="win32" #Architecture of the wine prefix
WINE_PREFIX_GAME_DIR="drive_c/Games/InterstellarRift" #Server executable directory
WINE_PREFIX_GAME_EXE="Build/IR.exe -server -inline" #Server executable

#Ramdisk configuration
TMPFS_ENABLE="1" #Set this to 1 if you want to run the server on a ramdisk
TMPFS_DIR="/home/$USER/tmpfs/$SRV_DIR_NAME" #Locaton of your ramdisk. Note: you have to configure the ramdisk in /etc/fstab before using this.

#TmpFs/hdd variables
if [[ "$TMPFS_ENABLE" == "1" ]]; then
	SCREEN_LOG="$TMPFS_DIR/$WINE_PREFIX_GAME_DIR/Build/screenlog.0" #Application data of the tmpfs
	BCKP_SRC_DIR="$TMPFS_DIR/drive_c/users/$USER/Application Data/InterstellarRift/" #Application data of the tmpfs
	SERVICE="$SERVICE_NAME-tmpfs.service" #TmpFs service file name
elif [[ "$TMPFS_ENABLE" == "0" ]]; then
	SCREEN_LOG="$SRV_DIR/$WINE_PREFIX_GAME_DIR/Build/screenlog.0" #Application data of the hdd/ssd
	BCKP_SRC_DIR="$SRV_DIR/drive_c/users/$USER/Application Data/InterstellarRift/" #Application data of the hdd/ssd
	SERVICE="$SERVICE_NAME.service" #Hdd/ssd service file name
fi

#Backup configuration
BCKP_SRC="*" #What files to backup, * for all
BCKP_DIR="/home/$USER/servers/$SRV_DIR_NAME/backups" #Location of stored backups
BCKP_DEST="$BCKP_DIR/$(date +"%Y")/$(date +"%m")/$(date +"%d")" #How backups are sorted, by default it's sorted in folders by month and day
BCKP_DELOLD="+3" #Delete old backups. Ex +3 deletes 3 days old backups.

#-------Do not edit anything beyond this line-------

#Console collors
RED='\033[0;31m'
GREEN='\033[0;32m'
CYAN='\033[0;36m'
LIGHTRED='\033[1;31m'
NC='\033[0m'

#Prints out if the server is running
script_status() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Status) Server is not running." | tee -a  "$SCRIPT_LOG"
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Status) Server running." | tee -a  "$SCRIPT_LOG"
	fi
}

#If the script variable is set to 0, the script won't issue any commands ran. It will just exit.
script_enabled() {
	if [[ "$SCRIPT_ENABLED" == "0" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Script status) Server script is disabled" | tee -a  "$SCRIPT_LOG"
		script_status
		exit 0
	fi
}

#Sync server files from hdd/ssd to ramdisk
script_rsynctotmpfs() {
	rsync -av --info=progress2 $SRV_DIR/ $TMPFS_DIR
}

#Sync server files from ramdisk to hdd/ssd
script_rsyncfromtmpfs() {
	rsync -av --info=progress2 $TMPFS_DIR/ $SRV_DIR #| sed -e "s/^/$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Sync) Syncing: /" | tee -a  "$SCRIPT_LOG"
}

script_crash_kill() {
	if [[ "$(ps aux | grep -i "[A]lunaCrashHandler.exe" | awk '{print $2}')" -gt "0" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Aluna Crash Handler) AlunaCrashHandler.exe detected. Killing the process." | tee -a  "$SCRIPT_LOG"
		kill $(ps aux | grep -i "[A]lunaCrashHandler.exe" | awk '{print $2}')
		if [[ "$(ps aux | grep -i "[A]lunaCrashHandler.exe" | awk '{print $2}')" -eq "" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Aluna Crash Handler) AlunaCrashHandler.exe process killed." | tee -a  "$SCRIPT_LOG"
		elif [[ "$(ps aux | grep -i "[A]lunaCrashHandler.exe" | awk '{print $2}')" -gt "0" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Aluna Crash Handler) Failed to kill AlunaCrashHandler.exe process." | tee -a  "$SCRIPT_LOG"
		fi
	elif [[ "$(ps aux | grep -i "[A]lunaCrashHandler.exe" | awk '{print $2}')" -eq "" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Aluna Crash Handler) AlunaCrashHandler.exe not detected. Server nominal." | tee -a  "$SCRIPT_LOG"
	fi
}

#Issue the save command to the server
script_save() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Server is not running." | tee -a  "$SCRIPT_LOG"
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Save game to disk has been initiated." | tee -a  "$SCRIPT_LOG"
		screen -p 0 -S $NAME -X eval 'stuff "/save"\\015'
		#while [ "$(tail -n 1 $SCREEN_LOG )" != '[Server]: Save completed.' ]; do
			#echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Server is saving Please wait..."
			#sleep 1
		#done
		sleep 5
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Save game to disk has been completed." | tee -a  "$SCRIPT_LOG"
	fi
}

#Sync server files from ramdisk to hdd/ssd
script_sync() {
	if [[ "$TMPFS_ENABLE" == "1" ]]; then
		if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Sync) Server is not running." | tee -a  "$SCRIPT_LOG"
		elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Sync) Sync from tmpfs to disk has been initiated." | tee -a  "$SCRIPT_LOG"
			script_rsyncfromtmpfs
			sleep 1
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Sync) Sync from tmpfs to disk has been completed." | tee -a  "$SCRIPT_LOG"
		fi
	elif [[ "$TMPFS_ENABLE" == "0" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Sync) Server does not have tmpfs enabled." | tee -a  "$SCRIPT_LOG"
	fi
}

#Start the server
script_start() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "inactive" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server start initialized." | tee -a  "$SCRIPT_LOG"
		systemctl --user start $SERVICE
		sleep 1
		while [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "activating" ]]; do
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server is activating. Please wait..." | tee -a  "$SCRIPT_LOG"
			sleep 1
		done
		if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server has been successfully activated." | tee -a  "$SCRIPT_LOG"
			sleep 1
		elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server failed to activate. See systemctl --user status $SERVICE for details." | tee -a  "$SCRIPT_LOG"
			sleep 1
		fi
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server is already running." | tee -a  "$SCRIPT_LOG"
		sleep 1
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "failed" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Start) Server failed to activate. See systemctl --user status $SERVICE for details." | tee -a  "$SCRIPT_LOG"
		sleep 1
	fi
}

#Stop the server
script_stop() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "inactive" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Stop) Server is not running." | tee -a  "$SCRIPT_LOG"
		sleep 1
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Stop) Server shutdown in progress." | tee -a  "$SCRIPT_LOG"
		systemctl --user stop $SERVICE
		sleep 1
		while [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "deactivating" ]]; do
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Stop) Server is deactivating. Please wait..." | tee -a  "$SCRIPT_LOG"
			sleep 1
		done
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Stop) Server is deactivated." | tee -a  "$SCRIPT_LOG"
	fi
}

#Restart the server
script_restart() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "inactive" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Restart) Server is not running." | tee -a  "$SCRIPT_LOG"
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Restart) Server is going to restart in 15-30 seconds, please wait..." | tee -a  "$SCRIPT_LOG"
		sleep 1
		screen -p 0 -S $NAME -X eval 'stuff "/all Server restarting in 15 seconds."\\015'
		sleep 1
		script_stop
		sleep 1
		script_start
		sleep 1
	fi
}

#If the server proces is terminated it auto restarts it
script_autorestart() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Autorestart) Server not running, attempting to start." | tee -a  "$SCRIPT_LOG"
		script_start
		sleep 1
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Autorestart) Server running, no need to restart." | tee -a  "$SCRIPT_LOG"
	fi
}

#Deletes old backups
script_deloldbackup() {
	# Delete old backups
	find $BCKP_DIR -mtime $BCKP_DELOLD -exec rm {} \;
	# Delete empty folders
	find $BCKP_DIR -type d 2> /dev/null -empty -exec rm -rf {} \;
}

#Backs up the server
script_backup() {
	# If there is not a folder for today, create one
	if [ ! -d "$BCKP_DEST" ]; then
		mkdir -p $BCKP_DEST
	fi
	#Create the new backup directory
	if [ ! -d "$BCKP_DEST" ]; then
		mkdir -p $BCKP_DEST
	fi
	# Backup source to destination
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Backup) Backup has been initiated." | tee -a  "$SCRIPT_LOG"
	cd "$BCKP_SRC_DIR"
	tar -cpvzf $BCKP_DEST/$(date +"%Y%m%d%H%M").tar.gz $BCKP_SRC #| sed -e "s/^/$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Backup) Compressing: /" | tee -a  "$SCRIPT_LOG"
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Backup) Backup complete." | tee -a  "$SCRIPT_LOG"
}

#Automaticly backs up the server and deletes old backups
script_autobackup() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Autobackup) Server is not running." | tee -a  "$SCRIPT_LOG"
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		sleep 1
		script_backup
		sleep 1
		script_deloldbackup
	fi
}

#Check for updates and update the server, if there are updates available, shut down the server, update it and restart it.
script_update() {
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Initializing update check." | tee -a  "$SCRIPT_LOG"
	if [ ! -f $UPDATE_DIR/installed.buildid ] ; then
		touch $UPDATE_DIR/installed.buildid
		echo "0" > $UPDATE_DIR/installed.buildid
	fi
	if [ ! -f $UPDATE_DIR/installed.timeupdated ] ; then
		touch $UPDATE_DIR/installed.timeupdated
		echo "0" > $UPDATE_DIR/installed.timeupdated
	fi
	
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Removing Steam/appcache/appinfo.vdf" | tee -a  "$SCRIPT_LOG"
	rm -rf "/home/$USER/.steam/appcache/appinfo.vdf"
	
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Connecting to steam servers." | tee -a  "$SCRIPT_LOG"
	
	steamcmd +login $STEAMCMDUID $STEAMCMDPSW +app_info_update 1 +app_info_print $APPID +quit | grep -EA 1000 "^\s+\"branches\"$" | grep -EA 5 "^\s+\"public\"$" | grep -m 1 -EB 10 "^\s+}$" | grep -E "^\s+\"buildid\"\s+" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d' ' -f3 > $UPDATE_DIR/available.buildid
	
	steamcmd +login $STEAMCMDUID $STEAMCMDPSW +app_info_update 1 +app_info_print $APPID +quit | grep -EA 1000 "^\s+\"branches\"$" | grep -EA 5 "^\s+\"public\"$" | grep -m 1 -EB 10 "^\s+}$" | grep -E "^\s+\"timeupdated\"\s+" | tr '[:blank:]"' ' ' | tr -s ' ' | cut -d' ' -f3 > $UPDATE_DIR/available.timeupdated
	
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Received application info data." | tee -a  "$SCRIPT_LOG"
	
	INSTALLED_BUILDID=$(cat $UPDATE_DIR/installed.buildid)
	AVAILABLE_BUILDID=$(cat $UPDATE_DIR/available.buildid)
	INSTALLED_TIME=$(cat $UPDATE_DIR/installed.timeupdated)
	AVAILABLE_TIME=$(cat $UPDATE_DIR/available.timeupdated)
	
	if [ "$AVAILABLE_TIME" -gt "$INSTALLED_TIME" ]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) New update detected." | tee -a  "$SCRIPT_LOG"
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Installed: BuildID: $INSTALLED_BUILDID, TimeUpdated: $INSTALLED_TIME" | tee -a  "$SCRIPT_LOG"
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Available: BuildID: $AVAILABLE_BUILDID, TimeUpdated: $AVAILABLE_TIME" | tee -a  "$SCRIPT_LOG"
		sleep 1
		if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
			screen -p 0 -S $NAME -X eval 'stuff "/all New update detected. Server will shutdown and update."\\015'
			WAS_RUNNING="1"
			script_stop
		fi
		sleep 1
		if [[ "$TMPFS_ENABLE" == "1" ]]; then
			rm -rf $TMPFS_DIR/$WINE_PREFIX_GAME_DIR
		fi
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Updating..." | tee -a  "$SCRIPT_LOG"
		steamcmd +@sSteamCmdForcePlatformType windows +login $STEAMCMDUID $STEAMCMDPSW +force_install_dir $SRV_DIR/$WINE_PREFIX_GAME_DIR +app_update $APPID validate +quit
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Update completed." | tee -a  "$SCRIPT_LOG"
		echo "$AVAILABLE_TIME" > $UPDATE_DIR/installed.timeupdated
		if [ "$WAS_RUNNING" == "1" ]; then
			script_start
		fi
	elif [ "$AVAILABLE_TIME" -eq "$INSTALLED_TIME" ]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) No new updates detected." | tee -a  "$SCRIPT_LOG"
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Update) Installed: BuildID: $INSTALLED_BUILDID, TimeUpdated: $INSTALLED_TIME" | tee -a  "$SCRIPT_LOG"
	fi
}

#First timer function for systemd timers to execute parts of the script in order without interfering with each other
script_timer_one() {
	script_enabled
	script_crash_kill
	script_autorestart
	script_save
	script_sync
	script_autobackup
	script_update
}

#Second timer function for systemd timers to execute parts of the script in order without interfering with each other
script_timer_two() {
	script_enabled
	script_crash_kill
	script_autorestart
	script_save
	script_sync
	script_update
}

script_install() {
	echo "Installation 1/3"
	echo ""
	echo "Required packages that need to be installed on the server:"
	echo "xorg-xauth"
	echo "xorg-xhost"
	echo "wine"
	echo "screen"
	echo "steamcmd"
	echo ""
	echo "Required packages that need to be installed on the client:"
	echo "xorg-xauth"
	echo ""
	echo "If these packages aren't installed, terminate this script with CTRL+C and install them."
	echo ""
	echo "This installation will enable linger for the user specified (allows user services to be ran on boot)."
	echo "The installation process will also make a modification to /etc/ssh/sshd_config to allow X11 GUI forwarding to your"
	echo "local machine so you can install the wine prefix. For this to work edit your /etc/ssh/sshd_config on your"
	echo "local machine and uncomment the line:"
	echo "#X11Forwarding yes"
	echo "so it looks like this:"
	echo "X11Forwarding yes"
	echo "After that reboot both machines or restart the ssh services."
	echo ""
	read -p "Press any key to continue" -n 1 -s -r
	echo ""
	read -p "Enter user (MUST NOT BE ROOT!): " USER
	echo ""
	read -p "Enable RamDisk (1-yes, 0-no): " TMPFS
	echo ""
	if [[ "$TMPFS" == "1" ]]; then
		read -p "RamDisk Size (Minimum 6GB): " TMPFS_SIZE
	fi
	if [[ "$TMPFS" == "1" ]]; then
		cat >> /etc/fstab <<- EOF
	
		# /home/$USER/tmpfs
		tmpfs				   /home/$USER/tmpfs		tmpfs		   rw,size=$TMPFS_SIZE,uid=$USER	0 0
		EOF
	fi
	sudo sed -i 's/#AllowTcpForwarding yes/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
	sudo sed -i 's/#X11Forwarding yes/X11Forwarding yes yes/g' /etc/ssh/sshd_config 
	sudo sed -i 's/#X11DisplayOffset 10/X11DisplayOffset 10/g' /etc/ssh/sshd_config 
	sudo sed -i 's/#X11UseLocalhost yes/X11UseLocalhost yes/g' /etc/ssh/sshd_config 
	
	sudo mkdir -p /var/lib/systemd/linger/
	sudo touch /var/lib/systemd/linger/$USER
	
	echo "Installation 1/3 complete."
	echo "After you reboot the server and your local machine connect to the server with ssh -Y user@host"
}

script_install_services() {
	echo "Installation 2/3"
	echo ""
	echo "Initializing service instalation."
	echo ""
	echo "List of files that are going to be generated on the system:"
	echo ""
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-mkdir-tmpfs.service - Service to generate the folder structure once the RamDisk is started (only executes if RamDisk enabled)."
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-tmpfs - Server service file for use with a RamDisk (only executes if RamDisk enabled)."
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME - Server service file for normal hdd/ssd use."
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-timer-1.timer - Timer for scheduled command execution of $SERVICE_NAME-timer-1.service"
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-timer-1.service - Executes scheduled script functions: autorestart, save, sync, backup and update."
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-timer-2.timer - Timer for scheduled command execution of $SERVICE_NAME-timer-2.service"
	echo "/home/$USER/.config/systemd/user/$SERVICE_NAME-timer-2.service - Executes scheduled script functions: autorestart, save, sync and update."
	echo ""
	read -p "Press any key to continue" -n 1 -s -r
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-mkdir-tmpfs.service <<- EOF
	[Unit]
	Description=$NAME TmpFs dir creator
	After=home-$USER-tmpfs.mount
	
	[Service]
	Type=oneshot
	WorkingDirectory=/home/$USER/
	ExecStart=/bin/mkdir -p $TMPFS_DIR/$WINE_PREFIX_GAME_DIR/Build
	
	[Install]
	WantedBy=default.target
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-tmpfs.service <<- EOF
	[Unit]
	Description=$NAME TmpFs Server Service 
	After=network.target home-$USER-tmpfs.mount $SERVICE_NAME-mkdir-tmpfs.service
	
	[Service]
	Type=forking
	WorkingDirectory=$TMPFS_DIR/$WINE_PREFIX_GAME_DIR/Build/
	ExecStartPre=/usr/bin/rsync -av --info=progress2 $SRV_DIR/ $TMPFS_DIR
	ExecStart=/bin/bash -c 'screen -dmSL $NAME env WINEARCH=$WINE_ARCH WINEDEBUG=-all WINEPREFIX=$TMPFS_DIR wine $TMPFS_DIR/$WINE_PREFIX_GAME_DIR/$WINE_PREFIX_GAME_EXE'
	ExecStartPost=/usr/bin/sed -i 's/SCRIPTENABLED="1"/SCRIPTENABLED="0"/' $SCRIPT_DIR/$SCRIPT_NAME
	ExecStop=/usr/bin/sed -i 's/SCRIPTENABLED="1"/SCRIPTENABLED="0"/' $SCRIPT_DIR/$SCRIPT_NAME
	ExecStop=/usr/bin/screen -p 0 -S $NAME -X eval 'stuff "quittimer 15 Server shutting down in 15 seconds!"\\015'
	ExecStop=/bin/sleep 10
	ExecStop=/usr/bin/rsync -av --info=progress2 $TMPFS_DIR/ $SRV_DIR
	TimeoutStartSec=infinity
	TimeoutStopSec=300
	Restart=no
	
	[Install]
	WantedBy=default.target
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME.service <<- EOF
	[Unit]
	Description=$NAME Server Service
	After=network.target
	
	[Service]
	Type=forking
	WorkingDirectory=$SRV_DIR/$WINE_PREFIX_GAME_DIR/Build/
	ExecStart=/bin/bash -c 'screen -dmSL $NAME env WINEARCH=$WINE_ARCH WINEDEBUG=-all WINEPREFIX=$SRV_DIR wine $SRV_DIR/$WINE_PREFIX_GAME_DIR/$WINE_PREFIX_GAME_EXE'
	ExecStartPost=/usr/bin/sed -i 's/SCRIPTENABLED="1"/SCRIPTENABLED="0"/' $SCRIPT_DIR/$SCRIPT_NAME
	ExecStop=/usr/bin/sed -i 's/SCRIPTENABLED="1"/SCRIPTENABLED="0"/' $SCRIPT_DIR/$SCRIPT_NAME
	ExecStop=/usr/bin/screen -p 0 -S $NAME -X eval 'stuff "quittimer 15 Server shutting down in 15 seconds!"\\015'
	ExecStop=/bin/sleep 10
	TimeoutStartSec=infinity
	TimeoutStopSec=300
	Restart=no
	
	[Install]
	WantedBy=default.target
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-timer-1.timer <<- EOF
	[Unit]
	Description=$NAME Script Timer 1
	
	[Timer]
	OnCalendar=*-*-* 00:00:00
	OnCalendar=*-*-* 06:00:00
	OnCalendar=*-*-* 12:00:00
	OnCalendar=*-*-* 18:00:00
	Persistent=true
	
	[Install]
	WantedBy=timers.target
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-timer-1.service <<- EOF
	[Unit]
	Description=$NAME Script Timer 1 Service
	
	[Service]
	Type=oneshot
	ExecStart=$SCRIPT_DIR/$SCRIPT_NAME -timer_one
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-timer-2.timer <<- EOF
	[Unit]
	Description=$NAME Script Timer 2
	
	[Timer]
	OnCalendar=*-*-* *:15:00
	OnCalendar=*-*-* *:30:00
	OnCalendar=*-*-* *:45:00
	OnCalendar=*-*-* 01:00:00
	OnCalendar=*-*-* 02:00:00
	OnCalendar=*-*-* 03:00:00
	OnCalendar=*-*-* 04:00:00
	OnCalendar=*-*-* 05:00:00
	OnCalendar=*-*-* 07:00:00
	OnCalendar=*-*-* 08:00:00
	OnCalendar=*-*-* 09:00:00
	OnCalendar=*-*-* 10:00:00
	OnCalendar=*-*-* 11:00:00
	OnCalendar=*-*-* 13:00:00
	OnCalendar=*-*-* 14:00:00
	OnCalendar=*-*-* 15:00:00
	OnCalendar=*-*-* 16:00:00
	OnCalendar=*-*-* 17:00:00
	OnCalendar=*-*-* 19:00:00
	OnCalendar=*-*-* 20:00:00
	OnCalendar=*-*-* 21:00:00
	OnCalendar=*-*-* 22:00:00
	OnCalendar=*-*-* 23:00:00
	Persistent=true
	
	[Install]
	WantedBy=timers.target
	EOF
	
	cat > /home/$USER/.config/systemd/user/$SERVICE_NAME-timer-2.service <<- EOF
	[Unit]
	Description=$NAME Script Timer 2 Service
	
	[Service]
	Type=oneshot
	ExecStart=$SCRIPT_DIR/$SCRIPT_NAME -timer_two
	EOF
	
	if [[ "$TMPFS" == "1" ]]; then
		systemctl --user enable $SERVICE_NAME-mkdir-tmpfs.service
	fi
	
	systemctl --user enable $SERVICE_NAME-timer-1.timer $SERVICE_NAME-timer-2.timer
	
	echo "Creating folder structure for server..."
	mkdir -p /home/$USER/servers/$SRV_DIR_NAME/{backups,scripts,server,updates}
	echo "Installation 2/3 complete."
}

script_install_wine_prefix() {
	echo "Installation 3/3"
	echo ""
	echo "This will install the wine prefix. There will be some GUI interaction necessary."
	echo "The wine uninstaller window will pop up at one time. Uninstall evreything related to Mono."
	echo ""
	read -p "Press any key to continue" -n 1 -s -r
	env WINEARCH=$WINE_ARCH WINEDEBUG=-all WINEPREFIX=$SRV_DIR wineboot --init
	env WINEARCH=$WINE_ARCH WINEDEBUG=-all WINEPREFIX=$SRV_DIR wine uninstaller
	env WINEARCH=$WINE_ARCH WINEDEBUG=-all WINEPREFIX=$SRV_DIR winetricks corefonts vcrun2012 dotnet472
	echo ""
	echo "Instalation 3/3 complete."
}

#Do not allow for another instance of this script to run to prevent data loss
if [[ $(pidof -o %PPID -x $0) -gt "0" ]]; then
	echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] Another instance of this script is already running. Exiting to prevent data loss."
	exit 0
fi

case "$1" in
	-help)
		echo -e "${CYAN}Time: $(date +"%Y-%m-%d %H:%M:%S") ${NC}"
		echo -e "${CYAN}$NAME server script by 7thCore${NC}"
		echo ""
		echo -e "${LIGHTRED}Before doing anything edit the script and input your steam username and password for the auto update feature to work.${NC}"
		echo -e "${LIGHTRED}The variables for it are located at the very top of the script.${NC}"
		echo -e "${LIGHTRED}Also if you have Steam Guard on your mobile phone activated, disable it because steamcmd always asks for the${NC}"
		echo -e "${LIGHTRED}two factor authentication code and breaks the auto update feature. Use Steam Guard via email.${NC}"
		echo ""
		echo -e "${GREEN}start ${RED}- ${GREEN}Start the server${NC}"
		echo -e "${GREEN}stop ${RED}- ${GREEN}Stop the server${NC}"
		echo -e "${GREEN}restart ${RED}- ${GREEN}Restart the server${NC}"
		echo -e "${GREEN}autorestart ${RED}- ${GREEN}Automaticly restart the server if it's not running${NC}"
		echo -e "${GREEN}save ${RED}- ${GREEN}Issue the save command to the server${NC}"
		echo -e "${GREEN}sync ${RED}- ${GREEN}Sync from tmpfs to hdd/ssd${NC}"
		echo -e "${GREEN}backup ${RED}- ${GREEN}Backup files, if server running or not.${NC}"
		echo -e "${GREEN}autobackup ${RED}- ${GREEN}Automaticly backup files when server running${NC}"
		echo -e "${GREEN}deloldbackup ${RED}- ${GREEN}Delete old backups${NC}"
		echo -e "${GREEN}update ${RED}- ${GREEN}Update the server, if the server is running it wil save it, shut it down, update it and restart it.${NC}"
		echo -e "${GREEN}status ${RED}- ${GREEN}Display status of server${NC}"
		echo -e "${GREEN}install ${RED}- ${GREEN}Installs all the needed files for the script to run${NC}"
		echo -e "${GREEN}install-services ${RED}- ${GREEN}Installs systemd services for the server${NC}"
		echo -e "${GREEN}install-prefix ${RED}- ${GREEN}Installs the wine prefix to the coresponding folder. There will be a lot of GUI interaction involved.${NC}"
		echo ""
		echo -e "${LIGHTRED}If this is your first time running the script:${NC}"
		echo -e "${LIGHTRED}First use the -install argument (run only this command as root) and follow the instructions${NC}"
		echo -e "${LIGHTRED}Second, run the -install_services argument. It will install the services for the server.${NC}"
		echo -e "${LIGHTRED}Third, run the -install-prefix argument. It will install the wine prefix. There will be a lot of GUI interaction involved.${NC}"
		echo -e "${LIGHTRED}Lastly you can run the script with the -update argument to install the game.${NC}"
		echo -e "${LIGHTRED}Your server configuration file and SSK should be put in $SRV_DIR/drive_c/users/$USER/Application Data/InterstellarRift/${NC}"
		echo -e "${LIGHTRED}When all of this is done copy/move this script to $SCRIPT_DIR ${NC}"
		echo ""
		echo -e "${LIGHTRED}After that enable the correct service with: systemctl --user enable $SERVICE_NAME.service or"
		echo -e "${LIGHTRED}systemctl --user enable $SERVICE_NAME-tmpfs.service for the RamDisk variant (USE ONLY ONE!)${NC}"
		echo -e "${LIGHTRED}Now start the service with systemctl --user start $SERVICE_NAME.service or systemctl --user start $SERVICE_NAME-tmpfs.service${NC}"
		echo ""
		echo -e "${LIGHTRED}Example usage: ./$SCRIPT_NAME -start${NC}"
		echo ""
		echo -e "${CYAN}Have a nice day!${NC}"
		echo ""
		;;
	-start)
		script_start
		;;
	-stop)
		script_stop
		;;
	-restart)
		script_restart
		;;
	-save)
		script_save
		;;
	-sync)
		script_sync
		;;
	-backup)
		script_backup
		;;
	-autobackup)
		script_autobackup
		;;
	-deloldbackup)
		script_deloldbackup
		;;
	-autorestart)
		script_autorestart
		;;
	-update)
		script_update
		;;
	-status)
		script_status
		;;
	-install)
		script_install
		;;
	-install_services)
		script_install_services
		;;
	-install-prefix)
		script_install_wine_prefix
		;;
	-crash_kill)
		script_crash_kill
		;;
	-timer_one)
		script_timer_one
		;;
	-timer_two)
		script_timer_two
		;;
	*)
	echo "Usage: $0 {start|stop|restart|save|sync|backup|autobackup|deloldbackup|autorestart|update|status|install|install_services|install-prefix \"server command\"}"
	exit 1
	;;
esac

exit 0

The script is a heavily based systemd workflow. The function in question is the save function. There is a while statement in it that I tried myself but dosen't work so I commented it out. The server program constsntly runs so there is no exit status when the save command is ran and when it's finished.

Last edited by 7thCore (2019-06-16 10:31:22)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#6 2019-06-16 12:41:49

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,442
Website

Re: [SOLVED] Bash script to wait and listen for a string in a screen

7thCore wrote:

The script is a heavily based systemd workflow.

No, it isn't, and that's likely a source of the problem.  It (ab)uses systemd features, but also goes a long way to not do things the systemd way and reinvents countless many wheels.

I'd say simplify first:

For example, while comments are generally a good idea, they need to *add* information, not just clutter.  If you use good variable names and function names, comments can focus on logic rather than labeling.  You tend to have good descriptive variable names - though there is absolutely no reason for them to be all caps.  But here is a line that shows a particularly useless comment:

SCRIPT_NAME="$SERVICE_NAME-script.bash" #Script name

The comment tells us that the variable SCRIPT_NAME is the "Script name".  That adds nothing but clutter.

Your function names, in contrast, are not so meaningful, and the comments don't help, but just make it worse.  E.g:

#Sync server files from ramdisk to hdd/ssd
script_rsyncfromtmpfs() {
...

And then a bit later a completely different function:

#Sync server files from ramdisk to hdd/ssd
script_sync() {
...

How could one reading this code have any idea what either of these are actually designed to do?

Lastly, a vast majority of this code is to create some log file.  But you already have a journal if you are using systemd services.

Anyhow, the likely direct cause of your problems is as Jason already suggested.  Add a 'sync' command at the end of the functions that move things between tmpfs and the hdd.

Last edited by Trilby (2019-06-16 12:42:51)


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2019-06-16 14:11:59

seth
Member
Registered: 2012-09-03
Posts: 49,968

Re: [SOLVED] Bash script to wait and listen for a string in a screen

It would seem the

screen -p 0 -S $NAME -X eval 'stuff "/save"\\015'

triggers some async action, thus the commented while loop and whatever that is needs to finish before you start the rsync.

Blocking until a *very* specific line shows up in the logs is a wonky idea, what if the save fails or for other reasons doesn't provide that log entry?

There's a lot of "server" mumbo-jumbo, but the screen_log seems to be a local file?
What's the actual layout here? Do you have access/control to/over the "server" processes?

Online

#8 2019-06-16 14:39:10

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

It's a game. A game in dedicated server mode running in wine on my private arch server at home. The script is there to save the files, sync them to the hdd and back them up. Plus some other mumbo jumbo. And Yes I have complete access.

Last edited by 7thCore (2019-06-16 14:43:30)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#9 2019-06-16 14:41:15

seth
Member
Registered: 2012-09-03
Posts: 49,968

Re: [SOLVED] Bash script to wait and listen for a string in a screen

That doesn't explain anything ( and the game was given away in the script :-P )

Online

#10 2019-06-16 15:27:58

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

seth wrote:

Blocking until a *very* specific line shows up in the logs is a wonky idea, what if the save fails or for other reasons doesn't provide that log entry?

Is there a way to time out a while loop maybe?
Or maybe I could ask one of the devs if there is there is another specific line that says the server failed to save the world?

seth wrote:

There's a lot of "server" mumbo-jumbo, but the screen_log seems to be a local file?
What's the actual layout here? Do you have access/control to/over the "server" processes?

The screen log is a local file on the server.

The layout (if I corectly understand what you mean) is as follows:

The systemd service start the server on boot and shuts it down gracefully on shutdown (a ups makes sure of that if the power fails wich tends to happens a lot in my town). It also copies the wine prefix to tmpfs before stsrting and syncs them back on shutdown. The service also changes the SCRIPT_ENABLED variable to 1 so the script can execute commands, otherwise the systemd timers will execute the script and the script will just exit. Every 15 minutes the script checks if the service failed (the screen session terminates  if the service crashes and exits) and restarts the service, also checks if the AlunaCrashHandler.exe is running because the IR.exe server starts another instance of itself as a ghost client and connects to the server. Sometimes it crashes but after the crash handler does it's thing it restarts. However on Linux the crash handler freezes so I have the script set up to kill it and after that another instance of the ghost client pops up by itself. It also sends the save command to save the world files and then rsync syncs them to the hdd. Every 6 hours the InterstellarRift folder in wine's Application Data folder (where the world files and server configuration is stored) gets backed up. After that it issues the update command to auto update the game server if an update is available.

Then repeat.

That is basicly the workflow of the script.

If this is not the answer to the question you ware asking, im sorry but english is not my first language so sometimes I don't understand some things people ask/require of me.

Edit:

Tribly wrote:

SCRIPT_NAME="$SERVICE_NAME-script.bash" #Script name

This is just there for myself. Yes it is clutter but if I want to adapt the script for another game/app I don't have to go through the script and change everything.

These two functions will be combined into one because they're basicly the same thing. One only calls the other and has more echo commands in it.

 
#Sync server files from ramdisk to hdd/ssd
script_rsyncfromtmpfs() {
...
 
#Sync server files from ramdisk to hdd/ssd
script_sync() {
...

Last edited by 7thCore (2019-06-16 17:00:20)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#11 2019-06-16 19:49:33

seth
Member
Registered: 2012-09-03
Posts: 49,968

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Ok, the "server" is basically the "dedicated game server", ie. a local daemon, you talk to it through input and it responds (eg. by saving data) but it never actually terminates, correct? (everything else about the daenin crashing etc. is irrelevant here)

The while loop checking the last line of the log in a 1s interval is risky, because you might easily miss the relevant one if there's a message burst.
You rather want to do sth. like

while read line; do if [ "$line" = "…" ]; then foo; bar; break; fi; done < <(tail -n1 -f /path/to/log )

If you need to dogwatch that because there's no reliable way to know whether or not the dameon responded and wrote some log about it, things get more complicated because you'll have to fork that loop, fork a timered kill to that subshell and ultimately "wait" (man wait) for the subshell to terminate (which would happen either because it succeeds or the kill job kicks in)

Online

#12 2019-06-17 11:09:16

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

seth wrote:

Ok, the "server" is basically the "dedicated game server", ie. a local daemon, you talk to it through input and it responds (eg. by saving data) but it never actually terminates, correct? (everything else about the daenin crashing etc. is irrelevant here)

You are correct.



seth wrote:

The while loop checking the last line of the log in a 1s interval is risky, because you might easily miss the relevant one if there's a message burst.
You rather want to do sth. like

while read line; do if [ "$line" = "…" ]; then foo; bar; break; fi; done < <(tail -n1 -f /path/to/log )

Here is how i changed the save function:

script_save() {
	if [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" != "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Server is not running." | tee -a  "$SCRIPT_LOG"
	elif [[ "$(systemctl --user show -p ActiveState --value $SERVICE)" == "active" ]]; then
		echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Save game to disk has been initiated." | tee -a  "$SCRIPT_LOG"
		screen -p 0 -S $NAME -X eval 'stuff "save"\\015'
		while read line; do
		if [ "$line" = "[Server]: Save completed." ]; then
			echo "$(date +"%Y-%m-%d %H:%M:%S") [$NAME] [INFO] (Save) Save game to disk has been completed." | tee -a  "$SCRIPT_LOG"
			break
		fi
		done < <(tail -n1 -f $SCREEN_LOG)
	fi
}

But for some reason this dosen't work. It keeps listening even though the server printed out the correct text.

Here is the text from the server console:

save  <-- the command the script is sending
[Server]: Server is saving...
Updating player save data...
Saving systems...
Start saving all systems...
End saving all systems...
Saving player client data...
Saving players...
Saving fleets...
Saving crews...
Saving galaxy updatables...
Saving metadata...
[Server]: Save completed.

If i use the same function to check a txt file and while it's running edit the txt file to have the correct string, then the function does work.

Edit: if i cat the screen log there are no spaces but if i edit it with nano the screen log has spaces between the lines.

save

[Server]: Server is saving...

Updating player save data...

Saving systems...

Start saving all systems...

End saving all systems...

Saving player client data...

Saving players...

Saving fleets...

Saving crews...

Saving galaxy updatables...

Saving metadata...

[Server]: Save completed.

Last edited by 7thCore (2019-06-17 11:21:00)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#13 2019-06-17 11:50:58

seth
Member
Registered: 2012-09-03
Posts: 49,968

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Does the loop read the line? Does the match hit?
The output likely contains some silly CRLF, try

if [[ $line =~ "foobar" ]]

for a substring match.

Online

#14 2019-06-17 12:19:18

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

seth wrote:

Does the loop read the line? Does the match hit?
The output likely contains some silly CRLF, try

if [[ $line =~ "foobar" ]]

for a substring match.

I tried:

echo "$line"

in the loop to see if the loop works and it did. However the match didn't hit even if it looked the same.

However now I tried your suggestion:

if [[ $line =~ "foobar" ]]

And this works!

Last edited by 7thCore (2019-06-17 12:20:22)


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

#15 2019-06-17 12:38:27

seth
Member
Registered: 2012-09-03
Posts: 49,968

Re: [SOLVED] Bash script to wait and listen for a string in a screen

Probably due to the mess that is https://en.wikipedia.org/wiki/Newline - ie. there's probably an \r at the end of the line.

Please always remember to mark resolved threads by editing your initial posts subject - so others will know that there's no task left, but maybe a solution to find.
Thanks.

Online

#16 2019-06-17 12:46:20

7thCore
Member
Registered: 2018-06-09
Posts: 65

Re: [SOLVED] Bash script to wait and listen for a string in a screen

It's probably something like that yeah.

Thanks for all your effort and patience seth.


[ Arch x86_64 | linux | Asus Prime X570-Pro | AMD Ryzen 9 5900X @4,8Ghz | AMD RX580 | 32GB RAM DDR4 | Main, 2 Monitors ]
[ Arch x86_64 | linux | Asus Pro WS X570-Ace | AMD Ryzen 9 5950X @4,9Ghz | Intel A750 | 128GB RAM DDR4 | Server ]

The Linux philosophy is 'Laugh in the face of danger'. Oops. Wrong One. 'Do it yourself'. Yes, that's it.

Offline

Board footer

Powered by FluxBB