Is it possible to modify git config options for wild respos without manually editing the gitolite.conf file? - gitolite

Suppose I have pushed to and configured the wild repo foo/bar.
If I want to add a mailing list option to this repo, one way is to add the following to my gitolite.conf file.
repo foo/ba[r]
config hooks.mailinglist = foo#bar.com
However, this requires that I have access to the gitolite.conf which is part of gitolite-admin repository.
Is there any way an ordinary user could make this modification, without access to the admin configuration file?
Note that I have already perused the documentation to no avail.

I got the following answer from the gitolite mailing list. However, this answer does not handle wild cards in GIT_CONFIG_KEYS, so I modified it to handle this the same way gitolite does.
It sufficed the insert the following inside commands/config and then add config to the list of enabled options in .gitolite.rc.
#!/bin/bash
# Usage: ssh git#host config <repo> --get <name>
# ssh git#host config <repo> --set <name> <value>
# ssh git#host config <repo> --unset <name>
#
# Set a "git config" option on a repo. You must be an owner of the
# repo, and the config option name must be allowed by the gitolite.rc
# configuration.
die() { echo "$#" >&2; exit 1; }
usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
[ -z "$1" ] && usage
[ "$1" = "-h" ] && usage
[ -z "$GL_USER" ] && die GL_USER not set
repo="$1"; shift
gitolite owns "$repo" || die "repository '$repo' missing or you do not own it"
cd `gitolite query-rc GL_REPO_BASE`/"$repo".git || die "missing repository '$1'";
case $1 in
--get) action='--get'
shift
[ "$#" -eq 1 ] || usage
;;
--set) action='--set'
shift
[ "$#" -gt 1 ] || usage
;;
--unset)
action='--unset'
shift
[ "$#" -eq 1 ] || usage
;;
*) if [ "$#" -eq 1 ]
then action='--get'
else action='--set'
fi
;;
esac
name="$1"; shift
ALLOWED_CONFIG=$(gitolite query-rc GIT_CONFIG_KEYS)
export ALLOWED_CONFIG
export name
deny=$(perl -e '
my #validkeys = split( " ", ( $ENV{ALLOWED_CONFIG} || "" ) );
my #matched = grep { $ENV{name} =~ /^$_$/i } #validkeys;
if (#matched < 1) {print "Denied\n";}')
if [[ -n "$deny" ]]; then
die "config option '$name' not allowed by gitolite.rc"
exit 1
fi
# there is not much need to sanitise the input; by default all
# arguments to commands are restricted to these: -0-9a-zA-Z._\#/+ :,\%=
# (see Gitolite::Rc.pm, the variable is $REMOTE_COMMAND_PATT) however
# for safety we will check the value for consistency with $UNSAFE_PATT
UNSAFE_PATT='.*[`~#\$\&()|;<>]'
case $action in
--set) if expr "$*" : "$UNSAFE_PATT" >/dev/null
then
die "value '$*' contains unsafe characters"
else
git config "$name" "$*"
fi
;;
*) git config $action "$name"
;;
esac

Related

Suddenly Unable Run Shell Script Function

I have a file named 'wpautobuild.sh'. In that file I have a script that automatically sets up a development environment and website on a linux server.
I've been calling a function named wp_auto_build() in the script with the following command:
$ ./wpautobuild.sh; wp_auto_build --project=abctest1
This worked fine up until I closed my terminal session and restarted it. Now when I run that same command I get following error:
-jailshell: wp_auto_build: command not found
I have no idea why I could run it fine for a while, but now I cannot. Nothing changed in the file. Admittingly, I am not well experienced in writing shell scripts.
Here is wpautobuild.sh:
#!/bin/sh
###########
# Variables
###########
#Required Variables
#BashRC File
FILE_BASH="$HOME/.bashrc";
FILE_WPAB="$HOME/wpautobuild.sh";
#The parent folder for all your site files
PATH_DEV="/home/wm/public_html";
#MYSQL Variables
MYSQL_UN="someuser";
MYSQL_PW="somepass";
#Repositories
declare -A REPO_PATH;
REPO_PATH[jumpstart]="https://someuser#bitbucket.org/someuser/wp-jumpstart.git";
REPO_PATH[divi]="https://someuser#bitbucket.org/someuser/divilib.git";
declare -A WP_DB_PREFIX;
WP_DB_PREFIX[jumpstart]="wp_";
WP_DB_PREFIX[divi]="wp_";
#Color variables
GREEN="\033[0;32m";
RED="\033[0;31m";
BLUE="\033[0;34m";
NC="\033[0m"; # No Color
BOLD="\e[1m";
WPAB_CHECKED=false;
#configurable variables
PROJECT_NAME="";
BUILD_TYPE="divi";
DB_NAME="";
DB_FILE_NAME="";
DB_SR_SEARCH="";
DB_SR_REPLACE="";
##############
# Functions
##############
####################################
# WP Build Automation
####################################
handle_arguments() {
ARGUMENTS=($#);
for i in "${ARGUMENTS[#]}"
do
INDEX=`expr index "$i" =`;
case $i in
--project*)
PROJECT_NAME=${i:INDEX};
;;
--build*)
BUILD_TYPE=${i:INDEX};
;;
--dbname*)
DB_NAME=${i:INDEX};
;;
--mysqlun*)
MYSQL_UN=${i:INDEX};
;;
--mysqlpw*)
MYSQL_PW=${i:INDEX};
;;
--dbfilename*)
DB_FILE_NAME=${i:INDEX};
;;
--search*)
DB_SR_SEARCH=${i:INDEX};
;;
--replace*)
DB_SR_REPLACE=${i:INDEX};
;;
*)
echo -e "${RED}$i is not recognized as an argument.${NC}\n";
;;
esac
done;
if [[ -z $DB_NAME ]];
then
DB_NAME=$PROJECT_NAME;
fi
}
wp_auto_build() {
# The main script that runs all the necessary functions to set up a site
#
#
# Arguments
# --project - [required]
# - name of the project; determines directory name, domain, and db name
#
# --build - [optional]
# - [values] - jumpstart, divi
# - [default] - jumpstart
# - determines whether to install wp-jumpstart or divilib
#
# --dbname - [optional]
# - [default] - --project
# - determines the name of the database
TIMESTAMP_START=$( date +%s );
printf "\n\n${BLUE}${BOLD}****************************************\n";
printf "WP Autobuild Sarting Up...\n";
printf "****************************************${NC}\n\n";
#check argument number
if [ $# -eq 0 ]
then
printf "${RED}[FAILED] No arguments passed. --project is required.\n";
return;
fi
handle_arguments $#;
echo ;
echo "***********************************";
echo "Checking Current Configuration...";
echo "***********************************";
echo ;
# Check variables
check_config;
#checks the return code of check_config to make sure everything is good. If not stop script
if [ $? -eq 1 ]
then
return;
else
printf "\n${GREEN}Variables are good${NC}\n\n"
fi
# Check configure to make sure all commands and dependencies are there
check_CLI_dependencies;
#checks the return code of check_CLI_dependencies to make sure everything is good. If not stop script
if [ $? -eq 1 ]
then
return;
else
printf "\n${GREEN}Dependencies are good${NC}\n\n"
fi
WPAB_CHECKED=true;
echo "Please check the configuration. Type "Y" and then hit [ENTER] to continue; anything else to stop...";
read CONTINUE;
if [[ $CONTINUE != "Y" ]]; then
return
fi
printf "\n***********************************\n";
printf "Starting: WP Auto-Build...\n";
printf "***********************************\n";
#Setup subdomain
setup_subdomain;
#Setup Build DB
setup_build_DB;
#Search and Replace Build DB
run_SRDB;
#Update Plugins and Core
run_wp_update;
# Open in browser
open_wpab_site;
TIMESTAMP_END=$( date +%s );
RUNTIME=$(($TIMESTAMP_END - $TIMESTAMP_START));
printf "${GREEN}\n";
printf "***********************************\n";
printf "Done: WP Auto-Build...\n";
printf "Time: $RUNTIME secs\n";
printf "***********************************\n";
printf "${NC}\n";
}
setup_subdomain() {
#
# Adds a directory for the project and adds an alias in bash goto_{--project}.
#
# Arguments
# --project - [required]
# - name of the project; deteremines directory name, domain, and db name
#
# if false, then we are running the function individually and need to supply arguments, handle arguments and check variables
if [ $WPAB_CHECKED == 'false' ]
then
handle_arguments $#;
# ########################
# ADD INDIVIDUAL CHECKS
# ########################
fi
printf "${GREEN}Setting up subdomain for site...\n";
printf "************************************${NC}\n";
# Create subdomain using cpanel api
uapi --user=someuser SubDomain addsubdomain domain=$PROJECT_NAME rootdomain=somedomain.com dir=%2Fpublic_html%2F$PROJECT_NAME
}
setup_build() {
# Clones the build repository, deletes the git and then reinitializes it.
#
# Arguments
# --project - [required]
# - name of the project; deteremines directory name, domain, and db name
#
# --build - [optional]
# - [values] - jumpstart, divi
# - [default] - jumpstart
# - determines whether to install wp-jumpstart or divilib
# if false, then we are running the function individually and need to supply arguments, handle arguments and check variables
if [ $WPAB_CHECKED == 'false' ]
then
handle_arguments $#;
# ########################
# ADD INDIVIDUAL CHECKS
# ########################
fi
printf "\n${GREEN}Cloning $BUILD_TYPE repository...\n";
printf "*****************************************${NC}";
cd "$PATH_DEV/$PROJECT_NAME";
echo "";
#Clone Repository
git clone ${REPO_PATH[$BUILD_TYPE]} "$PATH_DEV/$PROJECT_NAME";
#Remove repository .git so we can reinitialize it
rm -rf "$PATH_DEV/$PROJECT_NAME/.git";
}
setup_build_DB() {
#
# Sets up WP wp-config.php file and WP database based on the file in .dev/sql
#
# Arguments
# --project - [required]
# - name of the project; deteremines directory name, domain
#
# --dbname - [required]
# - name of the databsae;
#
# --build - [required]
# - [values] - jumpstart, divi
# - [default] - jumpstart
# - database table prefix
#
# --mysqlun - [optional]
# - override default MYSQL_UN;
#
# --mysqlpw - [optional]
# - override default MYSQL_PW;
#
# if false, then we are running the function individually and need to supply arguments, handle arguments and check variables
if [ $WPAB_CHECKED == 'false' ]
then
handle_arguments $#;
# ########################
# ADD INDIVIDUAL CHECKS
# ########################
fi
cd "$PATH_DEV/$PROJECT_NAME";
printf "\n${GREEN}Creating database...\n";
printf "*****************************************${NC}\n";
#create db
uapi --user=someuser Mysql create_database name=wm_$PROJECT_NAME
printf "\n${GREEN}Assigning user to database...\n";
printf "*****************************************${NC}\n";
#assign user
uapi --user=someuser Mysql set_privileges_on_database user=dbuser database=wm_$PROJECT_NAME privileges=DELETE,UPDATE,CREATE,ALTER
printf "\n${GREEN}Importing database from .dev/sql directory...\n";
printf "*****************************************${NC}\n";
if [ $BUILD_TYPE == 'jumpstart' ]; then
wp db import "$PATH_DEV/$PROJECT_NAME/.dev/sql/wpjs-c8631c0.sql";
elif [ $BUILD_TYPE == 'divi' ]; then
wp db import "$PATH_DEV/$PROJECT_NAME/.dev/sql/divilib.sql";
fi
}
run_SRDB() {
#
# Ruin SRDB on the database
#
# Arguments
# --project - [required]
# - name of the project; deteremines directory name, domain
#
# --dbname - [required]
# - name of the databsae;
#
# --build - [required]
# - [values] - jumpstart, divi
# - [default] - jumpstart
# - database table prefix
#
# --mysqlun - [optional]
# - override default MYSQL_UN;
#
# --mysqlpw - [optional]
# - override default MYSQL_PW;
# if false, then we are running the function individually and need to supply arguments, handle arguments and check variables
if [ $WPAB_CHECKED == 'false' ]
then
handle_arguments $#;
# ########################
# ADD INDIVIDUAL CHECKS
# ########################
fi
printf "\n${GREEN}Running Search & Replace for URL...\n";
printf "*****************************************${NC}\n";
#cd "$PATH_DEV/$PROJECT_NAME/srdb";
if [ $BUILD_TYPE == 'jumpstart' ]; then
wp search-replace 'wpjs.local' "$PROJECT_NAME.somedomain.com"
elif [ $BUILD_TYPE == 'divi' ]; then
wp search-replace 'divilib.local' "$PROJECT_NAME.somedomain.com"
fi
}
run_wp_update() {
#
# Update Wordpress and Plugins
#
# Arguments
# --project - [required]
# - name of the project; deteremines directory name, domain
#
# --build - [required]
# - [values] - jumpstart, divi
# - [default] - jumpstart
# - database table prefix
# if false, then we are running the function individually and need to supply arguments, handle arguments and check variables
if [ $WPAB_CHECKED == 'false' ]
then
handle_arguments $#;
# ########################
# ADD INDIVIDUAL CHECKS
# ########################
fi
cd "$PATH_DEV/$PROJECT_NAME";
#Update Core
printf "\n${GREEN}Updating WP Core...\n";
printf "*****************************************${NC}\n";
wp core update;
#Update All Plugins
printf "\n${GREEN}Updating WP Plugins...\n";
printf "*****************************************${NC}\n";
wp plugin update --all;
#Update All Themes
printf "\n${GREEN}Updating WP Themes...\n";
printf "*****************************************${NC}\n";
wp theme update --all;
}
check_config() {
WPAB_STATUS=true;
echo "Required Variables...";
echo "***********************************";
#Project Name
if [ -z "$PROJECT_NAME" ]
then
printf "${RED}[FAILED] PROJECT_NAME is empty. This must be passed with --project.\n";
WPAB_STATUS=false;
else
#Site files
if [ -d "$PATH_DEV/$PROJECT_NAME" ]
then
printf "${RED}[FAILED] $PATH_DEV/$PROJECT_NAME is already a project directory.${NC}\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] PROJECT_NAME: $PROJECT_NAME${NC}\n";
fi
fi
#DB Name
if [ -z "$DB_NAME" ]
then
printf "${RED}[FAILED] DB_NAME is empty. ($DB_NAME)\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] DB_NAME: $DB_NAME${NC}\n";
fi
#Build Type
if [ $BUILD_TYPE != 'jumpstart' ] && [ $BUILD_TYPE != 'divi' ]
then
printf "${RED}[FAILED] BUILD_TYPE can olny be /"jumpstart/" or /"divi/" ($BUILD_TYPE).\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] BUILD_TYPE: $BUILD_TYPE${NC}\n";
fi
#.bashrc
if [ ! -f "$FILE_BASH" ]
then
printf "\n${RED}[FAILED] FILE_BASH does not exist ($FILE_BASH). This variable must point to your .bashrc file.${NC}\n";
WPAB_STATUS=false;
else
printf "\n${GREEN}[SUCCESS] FILE_BASH: $FILE_BASH${NC}\n";
fi
#Site files
if [ ! -d "$PATH_DEV" ]
then
printf "${RED}[FAILED] PATH_DEV does not exist ($PATH_DEV). This variable is the path to the PARENT of your sites' directory.${NC}\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] PATH_DEV: $PATH_DEV${NC}\n";
fi
#check repositories
if [ -z "${REPO_PATH[$BUILD_TYPE]}" ]
then
printf "${RED}[FAILED] REPO_PATH[$BUILD_TYPE] is empty. This variable should be a reference to the build repository. (${REPO_PATH[$BUILD_TYPE]})${NC}\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] REPO_PATH[$BUILD_TYPE]: ${REPO_PATH[$BUILD_TYPE]}${NC}\n";
fi
#MYSQL Credentials
if [ -z "$MYSQL_UN" ]
then
printf "${RED}[FAILED] MYSQL_UN is empty ($MYSQL_UN). This variable must be set to a MYSQL Username.\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] MYSQL_UN: $MYSQL_UN${NC}\n";
fi
if [ -z "$MYSQL_PW" ]
then
printf "${RED}[FAILED] MYSQL_PW is empty ($MYSQL_PW). This variable must be set to a MYSQL Password.\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] MYSQL_PW: $MYSQL_PW${NC}\n";
fi
echo ;
echo ;
echo "Optional Variables...";
echo "***********************************";
#Stop script
if [ $WPAB_STATUS == false ]
then
echo ;
printf "${RED}Something went wrong. Check the output. Killing process...${NC}\n";
return 1;
else
return 2;
fi
}
check_CLI_dependencies() {
WPAB_STATUS=true;
#check git
printf "\nChecking git...\n";
echo "**********************************************";
if ! [ -x "$(command -v git)" ];
then
printf "${RED}[FAILED] git is NOT accessible.${NC}\n\n" >&2
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] git is accessible.${NC}\n\n";
#check access to wp-jumpstart
printf "Checking: Checking access to ${REPO_PATH[$BUILD_TYPE]}\n";
git ls-remote "${REPO_PATH[$BUILD_TYPE]}" --exit-code;
# ls-remote returns anything other than 0, then you cannot access
if [ "$?" -ne 0 ];
then
printf "${RED}[FAILED] Unable to read from ${REPO_PATH[$BUILD_TYPE]}${NC}\n\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] Access to ${REPO_PATH[$BUILD_TYPE]} is good.${NC}\n\n";
fi
fi
#check mysql
printf "\nChecking mysql...\n";
echo "**********************************************";
if ! [ -x "$(command -v mysql)" ];
then
printf "${RED}[FAILED] mysql is NOT accessible.${NC}\n" >&2;
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] myqsl is accessible.${NC}\n";
# check_mysql_access returns anything other than 0, then you cannot access
if [ "$?" -ne 0 ];
then
printf "${RED}[FAILED] Unable to connect to MYSQL. Either credentials are not valid (UN: $MYSQL_UN PW: $MYSQL_PW) or MYSQL is not running. ${NC}\n\n";
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] Access to MYSQL is good.${NC}\n\n";
fi
fi
#check wp
printf "\nChecking wp-cli...\n";
echo "**********************************************";
if ! [ -x "$(command -v wp)" ];
then
printf "${RED}[FAILED] wp-cli is not installed correctly.${NC}\n" >&2
WPAB_STATUS=false;
else
printf "${GREEN}[SUCCESS] wp-cli is good.${NC}\n"
fi
#Stop script
if [ $WPAB_STATUS == false ]
then
echo ;
printf "${RED}Something went wrong. Check the output. Killing process...${NC}\n";
return 1;
else
return 2;
fi
}
#open site url in default browser
open_wpab_site () {
printf "\n${GREEN}Launching Website...\n";
printf "*****************************************${NC}\n";
printf "Opening url in default browser...";
start https://$PROJECT_NAME.somedomain.com
}
You are executing the script from the CLI, which actually spawns a sub-shell, runs your script and then terminates. When it terminates, all created environment variables and functions simply get thrown away. They never arrive in your current shell, so you can not call a function from your shell that's defined in your script.
If you want to define functions that are available in your current environment, you would need to source the script defining these or, since this is conforming to POSIX, use .. Usually, when defining functions that shall behave like custom built-in commands, you add the function definition to .bashrc or something similar or you source a script doing that from there.
I was actually wondering why you were able to call your wp_auto_build for some time. I assume you were testing your script by pasting it from your favorite text editor directly into the shell. This does define variables and functions in your current environment for sure.

Create menu from all users with /home/ directory in bash

I am trying to write a bash script to remove cookies and cache from installed browsers on shared Ubuntu machines. The problem I am facing is in creating a menu where you can select either ALL users or individual users.
I am trying to create a main menu that calls either of the 2 functions (a work in progress) to perform the tasks (I have commented out the commands to run for the meantime).
#!/bin/bash
# Remove Browser cache from Ubuntu 16.04 or Ubuntu 18.04
# Check running as root/sudo
if [ "$EUID" -ne 0 ] ;then
echo -e "Please run with;\nsudo $0"
exit
fi
# Enable extended globbing for the +(...) pattern
shopt -s extglob
## Check Ubuntu version
VERSION=$(lsb_release -d | awk -F":" '/Description/ {print $2}')
if [[ "$VERSION" = *"Ubuntu 18.04"* ]]; then
HOME_DIR="/home/ANT.DOMAIN.COM"
else
[[ "$VERSION" = *"Ubuntu 16.04"* ]]
HOME_DIR="/home/local/ANT"
fi
# Set Colours
RED='\033[1;31m'
YELLOW='\033[1;33m'
GREEN='\033[1;32m'
NC='\033[0m' # No Color
## Clear Browser Cache for ALL Users
clear_cache_all () {
mapfile -t PROFILES < <(find "$HOME_DIR" -mindepth 1 -maxdepth 1 -type d)
for PRO in "${PROFILES[#]}"
do
# Check FireFox installed
dpkg -s firefox &> /dev/null
if [ $? -eq 0 ]; then
#rm -rf "$PRO"/.mozilla/firefox/*.default/*.sqlite "$PRO"/.mozilla/firefox/*default/sessionstore.js
#rm -rf "$PRO"/.cache/mozilla/firefox/*.default/*
echo -e "FireFox Cookies & Cache Cleared for user ${GREEN}$USERNAME${NC}"
else
echo -e "${YELLOW}FireFox Not Installed...moving on${NC}"
fi
# Check Chromium installed
dpkg -s chromium-browser &> /dev/null
if [ $? -eq 0 ]; then
#rm -rf "$PRO"/.config/chromium/Default/
#rm -rf "$PRO"/.cache/chromium
echo -e "Chromium Cookies & Cache Cleared for user ${GREEN}$USERNAME${NC}"
else
echo -e "${YELLOW}Chromium Not Installed...moving on${NC}"
fi
# Check Chrome installed
dpkg -s google-chrome-stable &> /dev/null
if [ $? -eq 0 ]; then
#rm -rf "$PRO"/.config/google-chrome/Default/
#rm -rf "$PRO"/.cache/google-chrome
echo -e "Google Chrome Cookies & Cache Cleared for user ${GREEN}$USERNAME${NC}"
else
echo -e "${YELLOW}Google Chrome Not Installed...moving on${NC}"
fi
done
}
## Clear Cache for Individual Users
clear_cache_user () {
echo "stuff!"
}
# main menu function
main_menu () {
clear
if [ -d "$HOME_DIR" ]
then
mapfile -t USERS < <(find "$HOME_DIR" -mindepth 1 -maxdepth 1 -type d)
# Get basename for users
USERNAME="${USERS[#]##*/}"
string="#(${USERNAME[0]}"
for((i=1;i<${#USERNAME[#]};i++))
do
string+="|${USERNAME[$i]}"
done
string+=")"
select NAME in "Clear ALL" "${USERNAME[#]}" "Quit"
do
case $NAME in
"Clear ALL")
# Call clear_cache_all Function
clear_cache_all
exit
;;
$string)
# Call clear_cache_user Function
clear_cache_user
;;
"Quit")
exit
;;
*)
echo "Invalid option, please try again";;
esac
done
else
echo -e "${RED}Error: Cannot find home directories...exiting${NC}"
fi
}
### SCRIPT COMMANDS ###
main_menu
Ok, so I can think of two options for your problem. I'll try to follow the names of your variables.
As I can see in your code, you have already put in the variable "string" all the usernames, so my first idea is to use a read and a simple if:
read -P "Insert ALL for all users, the Username for a single user, or Quit to exit: " NAME
if [ $NAME = "ALL" ]
then
clear_cache_all
exit
elif [ $NAME = "Quit" ]
then
echo "Bye!"
exit
else
for i in "${string[#]}"
do
if [ "$i" == "$NAME" ] ; then
clear_cache_user($NAME) #Guessing you'll pass the username as a variable to the function
exit
fi
done
echo "Invalid option, please try again"
fi
The other option is to use the case statement, as you were using. The problem is that case doesn't work easy with arrays, so while it's "case / in", it doesn't mean it's checking if the variable is an element of the array. In case you are forced to use case (or are in love with it), check this two links for some solutions: this one and this one.
Hope this helps! Good luck!

Linux single instance shell script fails to open in correct workspace at times

I have written the following Linux shell script through snippits gleaned from the web (I'm very new to shell scripts), its purpose is to ensure only a single instance of a programme is run with the added option of specifying which workspace a programme will open to.
I'm sure much of the code could be better constructed, however it works with one bug, when some, like Thunderbird, are opened they ignore the workspace switch unless the workaround I've added is used, but why? and is there a better way?
The script uses wmctrl: sudo apt-get install wmctrl
Usage: single-switch programme_name [-ws(int)] where (int) is number of workspace (must exist), the -ws param must be the last listed
#!/bin/bash
if ! [ $1 ] ; then exit ; fi
if [ "?" = "$1" ] ; then
FILE=$(echo "$0" | rev | cut -d "/" -f1 | rev) # extract filename from path
echo "usage $FILE <program name> [-ws(int)]"
exit 1;
fi
TITLE=$1
NAME=""
for var in "$#"; do [ "$(echo ${var} | head -c3)" != '-ws' ] && NAME="$NAME $var" ; done # remove our param from command
ntharg() { shift $1 ; echo $1 ; }
PARAM=`ntharg $# "$#"` # get the last param
if [ "-ws" != "$(echo ${PARAM} | head -c3)" ]; then PARAM=-1 ; # check its ours
else
PARAM=$( echo "$PARAM" | egrep -o '[0-9]+' ) # get the number
PARAM=$((PARAM-1)) # decrement
fi
if [ $PARAM -ge 0 ] ; then
wmctrl -x -a "$TITLE" || ( wmctrl -s $PARAM && zenity --title="Launch $TITLE" --warning --text="$TITLE is starting" --timeout="1" ; $NAME )
# dummy message otherwise some (ie thunderbird) ignore switch
else
wmctrl -x -a "$TITLE" || $NAME & # no switch, just raise or run programme
fi
# Done.
#

bash logger: Cannot find a way to add MaxBackupIndex to this logger implementation

I have been trying to modify this logger implementation but I cannot manage to make it work. Here's a sample:
#!/bin/bash
TRUE=1
FALSE=0
############### Added for testing
logger_LOG_ENABLED=$TRUE
logger_rootLogger=$TRACE,f,s
logger_appender_f=file
logger_appender_f_dir=$(pwd)
logger_appender_f_file=test.log
logger_appender_f_roll_format=%Y%m
logger_appender_f_roll=$TRUE
logger_appender_f_maxBackupIndex=10
####################################
logger_abs(){
if [ "${1:0:1}" == "." ]; then
builtin echo ${rootDir}/${1}
else
builtin echo ${1}
fi
}
logger_check_app_dir(){
if [ "$logger_LOG_ENABLED" -eq $TRUE ]; then
dir=$(logger_abs $1)
if [ ! -d ${dir} ]; then
#log a seperation line
mkdir $dir
fi
fi
}
# Delete old log files
# $1 Log directory
# $2 Log filename
# $3 Log filename suffix
# $4 Max backup index
logger_delete_old_files(){
##### Added for testing
builtin echo "Running logger_delete_old_files $#" >&2
#####
if [ "$logger_LOG_ENABLED" -eq $TRUE ] && [ -n "$3" ] && [ "$4" -gt 0 ]; then
local directory=$(logger_abs $1)
local filename=$2
local maxBackupIndex=$4
local suffix=$(echo "${3}" | sed -re 's/[^.]/?/g')
local logFileList=$(find "${directory}" -mindepth 1 -maxdepth 1 -name "${filename}${suffix}" -type f | xargs ls -1rt)
local fileCnt=$(builtin echo -e "${logFileList}" | wc -l)
local fileToDeleteCnt=$(($fileCnt-$maxBackupIndex))
local fileToDelete=($(builtin echo -e "${logFileList}" | head -n "${fileToDeleteCnt}" | sed ':a;N;$!ba;s/\n/ /g'))
##### Added for testing
builtin echo "logger_delete_old_files About to start deletion ${fileToDelete[#]}" >&2
#####
if [ ${fileToDeleteCnt} -gt 0 ]; then
for f in "${fileToDelete[#]}"; do
#### Added for testing
builtin echo "Removing file ${f}" >&2
####
builtin eval rm -f ${f}
done
fi
fi
}
#Appender
# $1 Log directory
# $2 Log file
# $3 Log file roll ?
# $4 Appender Name
logger_filename(){
builtin echo "Running logger_filename $#" >&2
local format
local filename
logger_check_app_dir "${1}"
if [ ${3} -eq 1 ];then
local formatProp=${4}_roll_format
format=${!formatProp}
if [ -z ${format} ]; then
format=$logger_appender_file_format
fi
local suffix=.`date "+${format}"`
filename=${1}/${2}${suffix}
# Old log files deletion
local previousFilenameVar=int_${4}_file_previous
local maxBackupIndexVar=${4}_maxBackupIndex
if [ -n "${!maxBackupIndexVar}" ] && [ "${!previousFilenameVar}" != "${filename}" ]; then
builtin echo "logger_filename Stepped into if: $previousFilenameVar => ${!previousFilenameVar}" >&2
builtin eval export $previousFilenameVar=$filename
logger_delete_old_files "${1}" "${2}" "${suffix}" "${!maxBackupIndexVar}"
fi
else
filename=${1}/${2}
fi
builtin echo $filename
}
######################## Added for testing
filename_caller(){
builtin echo "filename_caller Call $1"
output=$(logger_abs $(logger_filename "${logger_appender_f_dir}" "${logger_appender_f_file}" "1" "logger_appender_f" ))
builtin echo ${output}
}
#### Previous logs generation
for i in {1101..1120}; do
file="${logger_appender_f_file}.2012${i:2:3}"
builtin echo "${file} $i"
touch -m -t "2012${i}0000" ${logger_appender_f_dir}/$file
done
for i in {1..4}; do
filename_caller $i
done
Here is the output
test.log.201201 1101
test.log.201202 1102
test.log.201203 1103
test.log.201204 1104
test.log.201205 1105
test.log.201206 1106
test.log.201207 1107
test.log.201208 1108
test.log.201209 1109
test.log.201210 1110
test.log.201211 1111
test.log.201212 1112
test.log.201213 1113
test.log.201214 1114
test.log.201215 1115
test.log.201216 1116
test.log.201217 1117
test.log.201218 1118
test.log.201219 1119
test.log.201220 1120
filename_caller Call 1
/web/com/138245668210919/test.log.201310
filename_caller Call 2
/web/com/138245668210919/test.log.201310
filename_caller Call 3
/web/com/138245668210919/test.log.201310
filename_caller Call 4
/web/com/138245668210919/test.log.201310
Running logger_filename /web/com/138245668210919 test.log 1 logger_appender_f
logger_filename Stepped into if: int_logger_appender_f_file_previous =>
Running logger_delete_old_files /web/com/138245668210919 test.log .201310 10
logger_delete_old_files About to start deletion /web/com/138245668210919/test.log.201201 /web/com/138245668210919/test.log.201202 /web/com/138245668210919/test.log.201203 /web/com/138245668210919/test.log.201204 /web/com/138245668210919/test.log.201205 /web/com/138245668210919/test.log.201206 /web/com/138245668210919/test.log.201207 /web/com/138245668210919/test.log.201208 /web/com/138245668210919/test.log.201209 /web/com/138245668210919/test.log.201210
Removing file /web/com/138245668210919/test.log.201201
Removing file /web/com/138245668210919/test.log.201202
Removing file /web/com/138245668210919/test.log.201203
Removing file /web/com/138245668210919/test.log.201204
Removing file /web/com/138245668210919/test.log.201205
Removing file /web/com/138245668210919/test.log.201206
Removing file /web/com/138245668210919/test.log.201207
Removing file /web/com/138245668210919/test.log.201208
Removing file /web/com/138245668210919/test.log.201209
Removing file /web/com/138245668210919/test.log.201210
Running logger_filename /web/com/138245668210919 test.log 1 logger_appender_f
logger_filename Stepped into if: int_logger_appender_f_file_previous =>
Running logger_delete_old_files /web/com/138245668210919 test.log .201310 10
logger_delete_old_files About to start deletion
Running logger_filename /web/com/138245668210919 test.log 1 logger_appender_f
logger_filename Stepped into if: int_logger_appender_f_file_previous =>
Running logger_delete_old_files /web/com/138245668210919 test.log .201310 10
logger_delete_old_files About to start deletion
Running logger_filename /web/com/138245668210919 test.log 1 logger_appender_f
logger_filename Stepped into if: int_logger_appender_f_file_previous =>
Running logger_delete_old_files /web/com/138245668210919 test.log .201310 10
logger_delete_old_files About to start deletion
I'd expect logger_filename function to step into the following if only when the calculated log filename is different from the previous one:
if [ -n "${!maxBackupIndexVar}" ] && [ "${!previousFilenameVar}" != "${filename}" ]; then
For this scenario to apply, I'd need ${!previousFilenameVar} to be correctly set, but it's not the case, so logger_filename steps into this if all the time which is really not necessary...
It looks like the issue is due to the following line not working properly:
builtin eval export $previousFilenameVar=$filename
I have a some theories to explain why:
in the original code, functions are declared and exported as readonly which makes them unable to modify global variable. I removed readonly declarations in the above sample, but probleme persists.
Function calls are performed in $() which should make them run into seperated shell instances so variable modified are not exported to the main shell
But I cannot manage to find a workaround to this issue...
Any help is appreciated, thanks in advance!
I simply decided to change the way logger_filename function is called:
#Appender
# $1 Log directory
# $2 Log file
# $3 Log file roll ?
# $4 Appender Name
# $5 Output filename variable
logger_filename(){
#return result
local format
local filename
logger_check_app_dir "${1}"
if [ ${3} -eq 1 ];then
local formatProp=${4}_roll_format
format=${!formatProp}
if [ -z ${format} ]; then
format=$logger_appender_file_format
fi
local suffix=.`date "+${format}"`
filename=${1}/${2}${suffix}
# Old log files deletion
local previousFilenameVar=${4}_file_previous
local maxBackupIndexVar=${4}_maxBackupIndex
if [ -n "${!maxBackupIndexVar}" ] && [ "${!previousFilenameVar}" != "${filename}" ]; then
eval $previousFilenameVar=$filename
logger_delete_old_files "${1}" "${2}" "${suffix}" "${!maxBackupIndexVar}"
fi
else
filename=${1}/${2}
fi
#builtin echo $filename
eval $5=$filename
}
local logFileName=
logger_filename "${logFileDir}" "${logFile}" "${logFileRoll}" "${3}" logFileName
builtin echo "$2" >>"$(logger_abs "${logFileName}")"
This way the function is not executed in a subshell and variable ${!previousFilenameVar} is kept in the scope.

Ash MATCH operator (=~)

I'm trying to fit a script for linux onto my WD world edition drive.
The script is written for Bash (debian) but my WD only runs busybox (with ash). Despite this, I have gotten most functionality in there just from using Google. There is only one operator i have not found a counterpart to, the =~ operator
How can i port the functionality of the =~ operator from the old script to ash?
Script:
#! /bin/bash
# posttorrent.sh by Killemov
{
# Log file, file where we tell what events have been processed.
LOG_FILE=/var/log/posttorrent.log
# Username for transmission remote.
TR_USERNAME="username"
# Password for transmission remote.
TR_PASSWORD="password"
# Get current time.
NOW=$(date +%Y-%m-%d\ %H:%M:%S)
# Source directory, should not be changed.
SRC_DIR="${TR_TORRENT_DIR}/${TR_TORRENT_NAME}"
# Directory to store the un-compressed files in..
DEST_DIR="${TR_TORRENT_DIR}/${TR_TORRENT_NAME}/"
# This parameter string could be passed from Transmission in the future.
TR_TORRENT_PARAMETER="EXTRACT SLEEP1h"
echo "text"
if [ -e "$SRC_DIR/keep" ]; then
TR_TORRENT_PARAMETER="$TR_TORRENT_PARAMETER KEEP"
fi
if [ -e "$SRC_DIR/exit" ]; then
TR_TORRENT_PARAMETER="EXIT"
fi
# Actual processing starts here.
if [[ "$TR_TORRENT_PARAMETER" =~ "EXIT" ]]; then
echo $NOW "Exiting $TR_TORRENT_NAME" >> $LOG_FILE
exit 0
fi
echo "text2"
if [[ "$TR_TORRENT_PARAMETER" =~ "EXTRACT" ]]; then
cd $TR_TORRENT_DIR
if [ -d "$SRC_DIR" ]; then
IFS=$'\n'
unset RAR_FILES i
for RAR_FILE in $( find "$SRC_DIR" -iname "*.rar" ); do
if [[ $RAR_FILE =~ .*part.*.rar ]]; then
if [[ $RAR_FILE =~ .*part0*1.rar ]]; then
RAR_FILES[i++]=$RAR_FILE
fi
else
RAR_FILES[i++]=$RAR_FILE
fi
done
unset IFS
if [ ${#RAR_FILES} -gt 0 ]; then
for RAR_FILE in "$(eval \$$RAR_FILES[#])"; do
unrar x -inul "$RAR_FILE" "$DEST_DIR"
if [ $? -gt 0 ]; then
echo $NOW "Error unrarring $TR_TORRENT_NAME" >> $LOG_FILE
transmission-remote -n $TR_USERNAME:$TR_PASSWORD -t$TR_TORRENT_ID --verify --start
exit 0
fi
done
if [[ ! "$TR_TORRENT_PARAMETER" =~ "KEEP" ]]; then
SLEEP=$(expr match "$TR_TORRENT_PARAMETER" '.*SLEEP\([0-9a-zA-Z]*\)')
if [ ${#SLEEP} -gt 0 ]; then
sleep $SLEEP
fi
transmission-remote -n $TR_USERNAME:$TR_PASSWORD -t$TR_TORRENT_ID --remove-and-delete
fi
echo $NOW "Unrarred $TR_TORRENT_NAME" >> $LOG_FILE
fi
fi
fi
} &
(i had some trouble with indirect references, i hoped i fixed that correctly)
Well for the $VARIABLE =~ PATERN you should be able to use the:
echo "$VARIABLE" | grep -E PATTERN
But I think you will have a little bit of trouble with the arithmetical expressions i++ as well - if it's implemented, then you still need to use the i=$(($i + 1)) syntax, if it's not implemented, then the i=$(expr $i + 1) syntax.
I presume you're reason for the IFS=$'\n' is to split the find on newlines, but you're probably better off with issuing the find into a temporary file, and then doing a while read line; do ... done <$tmpfile,
Additionally, I'm not certain if all versions of busybox ash support arrays, so you may have a problem there as well.

Resources