Created
July 22, 2021 22:09
-
-
Save hinell/1bec392be04022e89de36e3e2acdfc5b to your computer and use it in GitHub Desktop.
Manage your tabs!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 <[email protected]> (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 <[email protected]> | |
# | |
# 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 <[email protected]> | |
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