Skip to content

Instantly share code, notes, and snippets.

@hinell
Created July 22, 2021 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hinell/1bec392be04022e89de36e3e2acdfc5b to your computer and use it in GitHub Desktop.
Save hinell/1bec392be04022e89de36e3e2acdfc5b to your computer and use it in GitHub Desktop.
Manage your tabs!
#!/usr/bin/env bash
# Title : console-tab
# Summary : Start dev environment. Supported platforms: Kubuntu 20.10
# Created-at : Wednesday, July 21, 2021
# Last-Modified : Thursday, July 22, 2021
# Repository : N/A
# Authors : Alex A. Davronov <al.neodim@gmail.com> (2021-)
# Description : TODO: Add description.
# Usage : Run $ .../console-tab usage
#
# @summary I detect which kind shell (zsh, bashh etc..) the script is run in.
# @usage $ declare currentShell="$(__shell.detect)";
# @param $shellName - A reference name for an output
# console-tab
# Copyright (C) 2021- Alex A. Davronov <al.neodim@gmail.com>
#
# Redistribution and (re)use of this Source or Binary code produced from such
# regardless of the carrier with or without modification is permitted free of
# charge (unless explicitly stated otherwise herewith) provided that
# the following conditions are met:
#
# 1. Redistributions of the Source code must retain the above
# Copyright notice, this List of conditions, and the following
# Disclaimer.
#
# 2. Redistributions of the Binary code must reproduce the above
# Copyright notice, this List of conditions, and the following
# Disclaimer visible prominently and clearly to the user's eyes
# within documentation provided with such distribution or at the
# user request immediately.
#
# 3. Failure to meet the List of condition set hereby terminates
# unconditionally your rights and permissions granted by the above
# Copyright notice and make you eligible for prosecution, lawsuit or any
# legal actions or proceedings under appropritate law of country of your
# residence or International law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
__shell.detect(){
type compdef &> /dev/null && { echo "zsh" ; return 0; };
type complete &> /dev/null && { echo "bash" ; return 0; };
}
___console_tabs.version(){ echo 'v1.1.0'; }
___console_tabs.updated(){ echo 'Thursday, July 22, 2021'; }
___console_tabs.export.name(){ echo "console-tab"; }
___console_tabs.pids.file.path(){ echo '/tmp/__dev_bash_pids.txt'; }
___console_tabs(){
# PIDs storage of running tasks
PIDSPATH="$(___console_tabs.pids.file.path)"
# @summary Read tasks PIDS into array
# @param $pids - Name-ref to an array to output PIDs to
tabs.tasks.read(){
local ____pids=${1:?Pids name-ref to the array expected}
[[ -a "$PIDSPATH" ]] && {
eval "$____pids=($(cat $PIDSPATH))"
}
} # function end
## @summary Returns 0 if there are any running tasks
## @return - 1 - if no tasks found
# @param $pids - Name-ref to an array with PIDs
tabs.tasks.any(){
local pidsRef=${1:? $'\n'"$0: pids ref is missing"};
local command;
local commandPath
# Cross platform expansion from a reference variable
local __pids=($(eval "echo \${${pidsRef}[@]}"))
local -i i len=${#__pids[@]};
local taskPid;
for ((i=0; i <= len; i++)); do
taskPid=${__pids[i]}
commandPath="/proc/$taskPid/cmdline"
if [[ "$taskPid" && -a $commandPath ]];
then
return 0
fi
done;
echo '' > "$PIDSPATH";
return 1
} # function end
# @summary I'm tasked with stopping running tasks.
# @description I iterate over PIDs provided via argument and kill processes.
# The pdis can be read into an array by $ tabs.tasks.read
# @usage
# @param $pids - Name-ref to an array with PIDs
tabs.tasks.stop(){
local pidsRef=${1:? $'\n'"$0: pids are missing"};
local commandPath;
# Cross platform expansion from a reference variable
local __pids=($(eval "echo \${${pidsRef}[@]}"))
local -i i stopped=0 len=${#__pids[@]};
local taskPid;
for ((i=0; i <= len; i++)); do
taskPid=${__pids[i]}
commandPath="/proc/$taskPid/cmdline"
[[ "$taskPid" && -a $commandPath ]] && {
command=$(cat $commandPath | tr -d '\0'); # Trim null bytes
echo -n " Stopping [$command...] "
# IMPORTANT: The minus sign before $taskPid is necessairy
kill -s SIGTERM -- -$taskPid # &> /dev/null
echo " done."
((stopped++))
}
# test $? -eq 0\
# && echo "Processes are done"\
# || echo "Error: no tasks running"
done;
echo "Total stopped: $stopped"
# Clean up currently running tasks
echo "" > "$PIDSPATH";
} # function end
# @summary I stop currently running tasks
# @return - 1 if no tasks to stop
tabs.stop(){
local pids=();
tabs.tasks.read pids;
if tabs.tasks.any pids;
then
echo "Old task pids are found. Trying to stop."
tabs.tasks.stop pids;
else
return 1
fi
} # function end
# @summary List currently running tasks
tabs.list(){
local pids=()
tabs.tasks.read pids
local -i running=0;
local command;
local commandPath
local -i i len=${#pids[@]};
local taskPid;
# prints content of the array
for ((i=0; i <= len; i++)); do
taskPid=${pids[i]}
commandPath="/proc/$taskPid/cmdline"
# https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html#Bash-Conditional-Expressions
if [[ -n "$taskPid" && -a "$commandPath" ]];
then
((running++));
command=$(cat $commandPath | tr -d '\0'); # Trim null bytes
cat <<-EOL
PID: $taskPid COMMAND: $command
EOL
fi
done;
echo "Running jobs: ${running}" # ${pids[@]}"
} # function end
## @summary Run specified commands in a separate terminal window.
# So far it supports only Kubuntu's Konsole.
# It run and restarts currently running tasks.
tabs.run(){
local pids=();
tabs.tasks.read pids;
tabs.tasks.stop pids || echo "Initializing development environment."
local COMMAND1="$1";
local doNotClose=
case $COMMAND1 in
# (pattern);& # <- if match execute next commands
(--hold) ;&
(-k|--keep)
doNotClose=1;
shift;
;;
esac
type konsole 1> /dev/null && {
for command; do
echo "$command";
# TODO: CONTINUE problem with run after death noe rprocessess
konsole \
${DEBUG:+--hold} \
${doNotClose:+--hold} \
--workdir "$(pwd)" \
--new-tab \
-e bash -ci "PATH=$PATH; $command & echo \$! >> $PIDSPATH; wait"
# -e bash -c "PATH=$PATH; $command & echo \$! >> $PIDSPATH; wait \$! \$\$"
tabs.list
done;
return
}
type gnome-terminal 1> /dev/null && {
for command; do
echo "$command";
gnome-terminal \
--tab \
-e bash -c "PATH=$PATH; $command & echo \$! >> $PIDSPATH; wait \$! \$\$"
tabs.list
done;
return
}
echo -e "Kubuntu 20.10 system with konsole 20.08 is expected. Contact author for help";
} # function end
# Show usage
tabs.usage(){
local VERSION=$(___console_tabs.version);
local UPDATED=$(___console_tabs.updated);
local NAME=$(___console_tabs.export.name);
# BUG: Spaces break the heredoc statement
cat <<-EOL
┌─────────────┬──┬───┐
│ $NAME │ │ + │
├─────────────┴──┴───┤
│> ///////////////// │
└────────────────────┘
Console Tabs Manager $VERSION ($UPDATED)
Run/List/Stop commands in separate tabs
$NAME run|list|stop|help|version|examples
run|r [-k] <"CommanA"> <"CommanB">...
Run each command in a separate tab. Quotes are mandatory.
Restart already started processes (SIGTERminating)
-k - keep tab opened (do not close on finish/EOL)
list|ls - List running tasks
stop|s|k - Stop running tasks (closes tabs)
version|v - Show version
h|help - Show this output
x|examples - Examples
See LICENSE file provided along with source code for additional info.
Copyright (C) 2021- Alex A. Davronov <al.neodim@gmail.com>
EOL
} # function end
# @summary Show examples
tabs.usage.examples(){
cat <<-EOL
EXAMPLES:
$ $NAME run -k "echo Hello" "echo World"
$ $NAME list - list opened tabs's pids & commands
$ $NAME stop - stops all tasks
EOL
} # tabs.usage.examples end
# @summary Entry point
# @usage
# @param $arg0 -
# @param $arg1 -
# @param $@ - Rest of arguments
cli(){
[[ $# -eq 0 ]] && {
tabs.usage
return 1;
}
local COMMAND1="$1"; shift;
case $COMMAND1 in
# (pattern);& # <- if match execute next commands
(s|k|stop|kill)
tabs.stop
return
;;
(ls|list)
tabs.list
return
;;
(r|run)
tabs.run "$@"
return
;;
(v|version) ;&
(-v|-version) ;&
(--v|--version)
___console_tabs.version
return
;;
(h|help) ;&
(-h|-help) ;&
(--h|--help)
tabs.usage
return
;;
(x|examples)
tabs.usage.examples
return
;;
esac
tabs.usage
} # cli end
cli "$@"
} # ___console_tabs end
# TODO: Move this function to the top if you want!
# @summary I detect which kind shell (zsh, bashh etc..) the script is run in.
# @usage $ declare currentShell="$(__shell.detect)";
# @param $shellName - A reference name for an output
__shell.detect(){
type compdef &> /dev/null && { echo "zsh" ; return 0; };
type complete &> /dev/null && { echo "bash" ; return 0; };
}
# If sourced (via bash source command or . (dot)) - export default function
# If run as script - run default function
if [[ ${BASH_SOURCE[0]} != $0 ]]; then
# Alias the exported function, if necessary
EXPORT_NAME="$(___console_tabs.export.name)"
eval "$EXPORT_NAME(){ ___console_tabs "\$@";}" &> /dev/null
case "$(__shell.detect)" in
(zsh)
# Exports for ZSH - FUCK ZSH
eval "typeset -f $EXPORT_NAME" &> /dev/null
;;
(bash);&
(*)
# Exports for Bash and the rest
eval "export -f $EXPORT_NAME"
;;
esac
else
___console_tabs "$@"
fi
# Ars longa, vita brevis/Life is short, but art is long!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment