Last active
January 28, 2025 07:15
-
-
Save sanjarcode/92aa6a164d16e51c343eed926047fb1f to your computer and use it in GitHub Desktop.
Dotfiles - Linux, MacOS shell primer files - .bashrc and others
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 | |
# CUSTOM Aliases ##################### | |
# git | |
alias gco="git checkout" | |
alias ga="git add" | |
alias gunadd="git restore --staged" # Unstage path1 path2... | |
alias gcan="git commit --amend --no-edit" | |
alias gcm="git commit -m" | |
function gcmp() { # git commit and push | |
gcm "$@" | |
git push | |
} | |
alias gst="git status" | |
alias gpp="git push" | |
alias gpl="git pull" | |
alias gls="git branch --sort=-committerdate" # git branch ls | |
function gplo() { | |
# `git pull other` branch | |
# for hands free other-than-current-branch-update, see https://stackoverflow.com/a/45622872 | |
# Assumption: remote and local branches have same name | |
# Todo, figure out remote branch name even if different and pull, so command always succeeds | |
# suppose you are on feat/xyz | |
# gplo staging # will update the staging | |
local_branch="$1" | |
remote_branch="origin/$1" | |
if [[ "$(git rev-parse --abbrev-ref $remote_branch)" == "origin/$local_branch" ]]; then | |
# Perform the pull operation | |
git fetch -u origin "$local_branch":"$local_branch" | |
else | |
echo "Error: Remote branch '$remote_branch' doesn't match local branch '$local_branch'" | |
echo "No action performed." | |
fi | |
} | |
function gsave() { | |
git stash save $@ | |
} | |
function gload() { | |
git stash apply "stash^{/$@}" | |
} | |
_gitstash_autocomplete() { | |
local cur | |
cur="${COMP_WORDS[COMP_CWORD]}" | |
COMPREPLY=( $(git stash list | sed -nE 's/stash@\{[0-9]+\}: (.*)/\1/p' | grep -i -- "$cur") ) | |
} | |
complete -F _gitstash_autocomplete gload | |
complete -F _gitstash_autocomplete gsave | |
# gh - GitHub CLI | |
# get "commit" link instead of "tree" link. | |
alias ghcc='gh browse --no-browser $(git rev-parse HEAD) --repo $(git remote get-url origin | sed -e "s#.*github.com[:/]\(.*\)\.git#\1#") | tr -d "\n"' | |
# See: https://github.com/cli/cli/issues/7502 | |
# Note: the --repo option is needed since `gh` doesn't work well when the repo is part of a fork chain | |
# the `git remote get-url` with `sed` is needed to get the value for `--repo`. `gh` doesn't have a way to get the repo name, yes, weird. | |
# the `git remote get-url` with `sed` works in all cases - cloned with git (SSH, HTTPS) or with `gh repo clone` | |
# flip, wait till it completes. Open notebook. Flip without waiting. Close the terminal window(Does not close the kernel). | |
alias pyflip='pyenv versions | grep "3" | xargs -I {} pyenv global {} > /dev/null 2>&1' | |
#alias jupyter-notebookk='pyenv versions | grep "3" | xargs -I {} pyenv global {} > /dev/null 2>&1 ;jupyter-notebook & pyenv versions | grep "3" | xargs -I {} pyenv global {} > /dev/null 2>&1' | |
alias jupyter-notebookk='pyenv versions | grep "3" | xargs -I {} pyenv global {} > /dev/null 2>&1 ;jupyter-notebook & pyenv versions | grep "3" | xargs -I {} pyenv global {} > /dev/null 2>&1 ; exit' | |
# for wiimote connection | |
alias wmote='wminput -c /etc/cwiid/wminput/gamepad' | |
#soft-reboot the computer | |
alias res='kill -9 -1' | |
#alias for youtube-dl all options | |
alias youtube-dl='youtube-dl -i --write-sub --write-auto-sub --sub-lang en --embed-subs' | |
# write stylus app | |
alias Write="/opt/not_installed/write300/Write/Write" | |
#alias for simple mysql interpreter | |
alias mysqli='mycli -u sanjarPractice -ppassword' | |
#alias for going incognito in the terminal | |
alias incogT="unset HISTFILE" | |
# for lifelogger | |
alias l="lifelogger" | |
# CUSTOM Functions ##################### | |
# print (-s option) or navigate to Git repo root, current location or specified one | |
function groot { | |
local show= | |
local path= | |
# Parse command line options | |
while [[ $# -gt 0 ]]; do | |
case "$1" in | |
-s) | |
show=true | |
shift | |
;; | |
*) | |
path="$1" | |
shift | |
;; | |
esac | |
done | |
# If no path is specified, use the current directory | |
if [[ -z "$path" ]]; then | |
path="." | |
fi | |
# Get the Git root directory and either change to it or print it | |
local dir="$(cd "$path" && git rev-parse --show-toplevel 2>/dev/null)" | |
if [[ -n "$dir" ]]; then | |
dir="$(echo "$dir" | tr -d '\n')" | |
if [[ -n "$show" ]]; then | |
echo "$dir" | |
else | |
cd "$dir" || return | |
fi | |
else | |
echo "Not inside a Git repository" >&2 | |
return 1 | |
fi | |
} | |
# print random human-friendly name | |
function namegen { | |
jsCode=$(cat <<-ENDJS | |
const { | |
uniqueNamesGenerator, | |
adjectives, | |
colors, | |
animals | |
} = require('unique-names-generator'); | |
const output = uniqueNamesGenerator({ | |
dictionaries: [adjectives, colors, animals], | |
separator: '-' | |
}); | |
console.log(output); | |
ENDJS | |
) | |
node -e "$jsCode" | |
# npm package - https://www.npmjs.com/package/unique-names-generator#user-content-usage | |
# multiline bash - "here document" (chatGPT) - https://chat.openai.com/chat/21ad89f6-231f-4f92-8256-52c0f652fdcb | |
# node -e "some js code" option is available | |
} | |
function slow() { | |
# default waiting time | |
wait_time=0.5 | |
if [ "$1" -lt 5 ]; then | |
wait_time="$1" | |
return | |
fi | |
# if [ "$2" != '' ]; then | |
# $wait_time=$2 | |
# fi | |
# do the work using awk | |
"$@" | awk '{system("sleep '$wait_time'");print}' | |
} | |
function youtube-dl-numbered() { | |
# runs the alias | |
youtube-dl -cio "%(playlist_index)02d: %(title)s.%(ext)s" --write-sub --write-auto-sub --sub-lang en --embed-subs "$@" | |
} | |
function reposize() { | |
# https://webapps.stackexchange.com/questions/39587/view-estimated-size-of-github-repository-before-cloning | |
printf "$1" | perl -ne 'print $1 if m!([^/]+/[^/]+?)(?:\.git)?$!' | xargs -i curl -s -k https://api.github.com/repos/'{}' | grep size | tr -d -c 0-9 | awk '{printf $1/1024}' | |
echo " MB" | |
} | |
#advanced grep - works for images and pdfs too | |
function advgrep() { | |
grep "$1" -ri -I # text files | |
pdfgrep "$1" -ri # PDFs | |
# images | |
GRAY='\033[1;32m' | |
NC='\033[0m' # No Color | |
for file in $(find . -name '*.*g'); do | |
tesseract "$file" stdout 2>/dev/null | grep "$1" -i && echo -e "${GRAY}$file${NC}\n" | |
done | |
} | |
# gitify prompt, taken from the Udacity Git course | |
function gitify_prompt() { | |
red="\[\033[38;5;203m\]" | |
green="\[\033[38;05;38m\]" | |
blue="\[\033[0;34m\]" | |
reset="\[\033[0m\]" | |
export GIT_PS1_SHOWDIRTYSTATE=1 | |
# '\u' adds the name of the current user to the prompt | |
# '\$(__git_ps1)' adds git-related stuff | |
# '\W' adds the name of the current directory | |
export PS1="$red\u$green\$(__git_ps1)$blue \W | |
$ $reset" | |
# Changes colors for tty consoles | |
if [ "$TERM" = "linux" ]; then | |
echo -en "\e]P0232323" #black | |
echo -en "\e]P82B2B2B" #darkgrey | |
echo -en "\e]P1D75F5F" #darkred | |
echo -en "\e]P9E33636" #red | |
echo -en "\e]P287AF5F" #darkgreen | |
echo -en "\e]PA98E34D" #green | |
echo -en "\e]P3D7AF87" #brown | |
echo -en "\e]PBFFD75F" #yellow | |
echo -en "\e]P48787AF" #darkblue | |
echo -en "\e]PC7373C9" #blue | |
echo -en "\e]P5BD53A5" #darkmagenta | |
echo -en "\e]PDD633B2" #magenta | |
echo -en "\e]P65FAFAF" #darkcyan | |
echo -en "\e]PE44C9C9" #cyan | |
echo -en "\e]P7E5E5E5" #lightgrey | |
echo -en "\e]PFFFFFFF" #white | |
clear #for background artifacting | |
fi | |
} | |
# To use the Heroku CLI's autocomplete -- | |
# Via homebrew's shell completion: | |
# 1) Follow homebrew's install instructions https://docs.brew.sh/Shell-Completion | |
# NOTE: For zsh, as the instructions mention, be sure compinit is autoloaded | |
# and called, either explicitly or via a framework like oh-my-zsh. | |
# 2) Then run | |
# $ heroku autocomplete --refresh-cache | |
# OR | |
# Use our standalone setup: | |
# 1) Run and follow the install steps: | |
# $ heroku autocomplete | |
# CLI clipboard copy, paste | |
# Usage: `someCommand | c` copies the output to the clipboard | |
# Examples: `ls | c`, `cat someFile.txt | c`, `cat someFile.txt | grep 'hello' | c` | |
function copyAndPaste() { | |
if command -v xclip &> /dev/null | |
then | |
alias c="xclip -selection clipboard" | |
alias v="xclip -o -selection clipboard" | |
# echo "xclip exists" | |
return | |
fi | |
if command -v pbcopy &> /dev/null | |
then | |
alias c="cat | pbcopy" | |
alias p="pbpaste" | |
# echo "pbcopy exists" | |
return | |
fi | |
} | |
# kill process at port | |
# Usage: | |
# `portkill 3000` | |
# `portkill 8301 8302` (multiple arguments supported) | |
function portkill() { | |
for port in "$@"; do | |
fuser -k "$port/tcp" | |
done | |
} | |
# print total number of lines in files at path and all descendants | |
function countLines() { | |
find "$1" -type f -exec wc -l {} + | awk '{total += $1} END{print total}' | |
} | |
## bookmark setup for paths, START | |
## https://github.com/sanjar-notes/swe-culture-n-tools/issues/12 | |
## source: https://jeroenjanssens.com/navigate/ | |
export MARKPATH=$HOME/.marks | |
function jump { | |
cd -P "$MARKPATH/$1" 2>/dev/null || echo "No such mark: $1" | |
} | |
function mark { | |
mkdir -p "$MARKPATH"; ln -s "$(pwd)" "$MARKPATH/$1" | |
} | |
function unmark { | |
rm -i "$MARKPATH/$1" | |
} | |
function marks { | |
ls -l "$MARKPATH" | sed 's/ / /g' | cut -d' ' -f9- | sed 's/ -/\t-/g' && echo | |
} | |
function getmark { | |
echo $(realpath "$MARKPATH/$1") || echo "No such mark: $1" | |
} | |
function remark { | |
unmark "$1" | |
mark "$1" | |
} | |
_completemarks() { | |
local curw=${COMP_WORDS[COMP_CWORD]} | |
local wordlist=$(find $MARKPATH -type l -printf "%f\n") | |
COMPREPLY=($(compgen -W '${wordlist[@]}' -- "$curw")) | |
return 0 | |
} | |
complete -F _completemarks jump unmark remark getmark | |
# make shorter aliases for these | |
alias jp="jump" | |
alias mk="mark" | |
alias um="unmark" | |
alias mks="marks" | |
alias gm="getmark" | |
## bookmark setup END | |
# import function (run all top level files at path) | |
run_files_in_dir() { | |
local directory="$1" | |
if [ -d "$directory" ]; then | |
for file in "$directory"/*.sh; do | |
[ -e "$file" ] && source "$file" | |
done | |
else | |
# commented out - remains silent | |
# echo "Error: Directory not found - $directory" | |
: | |
fi | |
} | |
urlencode() { | |
local l=${#1} | |
for (( i = 0 ; i < l ; i++ )); do | |
local c=${1:i:1} | |
case "$c" in | |
[a-zA-Z0-9.~_-]) printf "$c" ;; | |
' ') printf + ;; | |
*) printf '%%%.2X' "'$c" | |
esac | |
done | |
} | |
urldecode() { | |
local data=${1//+/ } | |
printf '%b' "${data//%/\x}" | |
} | |
# usage | |
# obsidian path-to-vault | |
# obsidian path-to-vault note_path | |
# obsidian . | |
# note: ubuntu has problems with -z check, so file args don't work | |
function obsidian() { | |
value_git_based_name=$(basename $(cd $1; git root)) | |
value_current_dir_based_name=$(basename "$(realpath $1)") | |
vault_value=$([[ -z "$value_git_based_name" ]] && echo $value_current_dir_based_name || echo $value_git_based_name) | |
file_part=$([[ -z "$2" ]] && echo "" || "&file=$(urlencode $2)") | |
# echo "value_git_based_name:$value_git_based_name value_current_dir_based_name:$value_current_dir_based_name vault_value:$vault_value file_part$file_part" | |
xdg-open "obsidian://open?vault=$vault_value$file_part" >/dev/null 2>&1 & | |
} | |
# https://www.notion.so/sanjarcode/Serialize-Git-commits-for-storing-notes-procedures-10c20b93200480a4aa65f0ab22c7e2ac?pvs=4 | |
# Example: `generate_patch` (patches w.r.t main) | |
# Example: `generate_patch parent-branch-name` (patches w.r.t parent-branch-name) | |
generate_patch() { | |
local parent_branch="${1:-main}" # Default to 'main' if no argument is given | |
local current_branch=$(git rev-parse --abbrev-ref HEAD) # Get the current branch name | |
# Replace slashes with hyphens | |
current_branch="${current_branch//\//-}" | |
local patch_file="${current_branch}.patch" # Name the patch file after the current branch | |
# Get the base commit from the parent branch | |
local base_commit | |
base_commit=$(git merge-base "$parent_branch" HEAD) | |
# Generate the patch | |
git log -p "$base_commit..HEAD" -- ':!./*lock*' > "$patch_file" | |
echo "Patch generated: $patch_file" | |
} | |
_generate_patch() { | |
local branches | |
branches=$(git branch --format='%(refname:short)') # Get all branches | |
COMPREPLY=($(compgen -W "$branches" -- "${COMP_WORDS[1]}")) # Complete based on branches | |
} | |
complete -F _generate_patch generate_patch | |
# safely add my scripts, for home-controller | |
run_files_in_dir ~/.my-scripts /dev/null 2>&1 | |
$(startShutdownServerIdempotent > /dev/null 2>&1 &) |
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
# ~/.bashrc: executed by bash(1) for non-login shells. | |
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) | |
# for examples | |
# If not running interactively, don't do anything | |
case $- in | |
*i*) ;; | |
*) return;; | |
esac | |
# don't put duplicate lines or lines starting with space in the history. | |
# See bash(1) for more options | |
HISTCONTROL=ignoreboth | |
# append to the history file, don't overwrite it | |
shopt -s histappend | |
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) | |
HISTSIZE=1000 | |
HISTFILESIZE=2000 | |
# check the window size after each command and, if necessary, | |
# update the values of LINES and COLUMNS. | |
shopt -s checkwinsize | |
# If set, the pattern "**" used in a pathname expansion context will | |
# match all files and zero or more directories and subdirectories. | |
#shopt -s globstar | |
# make less more friendly for non-text input files, see lesspipe(1) | |
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" | |
# set variable identifying the chroot you work in (used in the prompt below) | |
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then | |
debian_chroot=$(cat /etc/debian_chroot) | |
fi | |
# set a fancy prompt (non-color, unless we know we "want" color) | |
case "$TERM" in | |
xterm-color|*-256color) color_prompt=yes;; | |
esac | |
# uncomment for a colored prompt, if the terminal has the capability; turned | |
# off by default to not distract the user: the focus in a terminal window | |
# should be on the output of commands, not on the prompt | |
#force_color_prompt=yes | |
if [ -n "$force_color_prompt" ]; then | |
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then | |
# We have color support; assume it's compliant with Ecma-48 | |
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such | |
# a case would tend to support setf rather than setaf.) | |
color_prompt=yes | |
else | |
color_prompt= | |
fi | |
fi | |
if [ "$color_prompt" = yes ]; then | |
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' | |
else | |
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' | |
fi | |
unset color_prompt force_color_prompt | |
# If this is an xterm set the title to user@host:dir | |
case "$TERM" in | |
xterm*|rxvt*) | |
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" | |
;; | |
*) | |
;; | |
esac | |
# enable color support of ls and also add handy aliases | |
if [ -x /usr/bin/dircolors ]; then | |
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" | |
alias ls='ls --color=auto' | |
#alias dir='dir --color=auto' | |
#alias vdir='vdir --color=auto' | |
alias grep='grep --color=auto' | |
alias fgrep='fgrep --color=auto' | |
alias egrep='egrep --color=auto' | |
fi | |
# colored GCC warnings and errors | |
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' | |
# some more ls aliases | |
alias ll='ls -alF' | |
alias la='ls -A' | |
alias l='ls -CF' | |
# Add an "alert" alias for long running commands. Use like so: | |
# sleep 10; alert | |
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' | |
# Alias definitions. | |
# You may want to put all your additions into a separate file like | |
# ~/.bash_aliases, instead of adding them here directly. | |
# See /usr/share/doc/bash-doc/examples in the bash-doc package. | |
if [ -f ~/.bash_aliases ]; then | |
. ~/.bash_aliases | |
fi | |
# enable programmable completion features (you don't need to enable | |
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile | |
# sources /etc/bash.bashrc). | |
if ! shopt -oq posix; then | |
if [ -f /usr/share/bash-completion/bash_completion ]; then | |
. /usr/share/bash-completion/bash_completion | |
elif [ -f /etc/bash_completion ]; then | |
. /etc/bash_completion | |
fi | |
fi | |
## ================== Post install variables | |
## nvm, node | |
export NVM_DIR="$HOME/.nvm" | |
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm | |
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion | |
# enable global 3rd party modules import - added by me | |
# CommonJS syntax works, ESM gives error (partially) | |
if [ -n "$NVM_BIN" ]; then | |
export NODE_PATH="${NVM_BIN/bin/lib/node_modules}" | |
export PATH="$PATH:$NODE_PATH" | |
else | |
___MYNODEPATH=$(npm root -g 2> /dev/null) | |
if [ -n "___MYNODEPATH" ]; then | |
export NODE_PATH=$___MYNODEPATH | |
export PATH="$PATH:$NODE_PATH" | |
fi | |
fi | |
## pyenv | |
if type pyenv &>/dev/null; then | |
export PYENV_ROOT="$HOME/.pyenv" | |
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" | |
eval "$(pyenv init -)" | |
# Load pyenv-virtualenv automatically by adding | |
eval "$(pyenv virtualenv-init -)" | |
fi | |
## rbenv, ruby | |
if type rbenv &>/dev/null; then | |
export PATH="$HOME/.rbenv/bin:$PATH" | |
eval "$(rbenv init -)" | |
fi | |
# pnpm start | |
export PNPM_HOME="/home/sanjar/.local/share/pnpm" | |
export PATH="$PNPM_HOME:$PATH" | |
# pnpm end | |
# AndroidStudio \w React Native setup docs | |
export ANDROID_SDK_ROOT=$HOME/.devTools/Android/Sdk | |
export PATH=$PATH:$ANDROID_SDK_ROOT/emulator | |
export PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools | |
# pnpm | |
export PNPM_HOME=$HOME/Library/pnpm | |
case ":$PATH:" in | |
*":$PNPM_HOME:"*) ;; | |
*) export PATH="$PNPM_HOME:$PATH" ;; | |
esac | |
# pnpm end | |
# place this after nvm initialization! | |
autoload -U add-zsh-hook | |
load-nvmrc() { | |
local nvmrc_path | |
nvmrc_path="$(nvm_find_nvmrc)" | |
if [ -n "$nvmrc_path" ]; then | |
local nvmrc_node_version | |
nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")") | |
if [ "$nvmrc_node_version" = "N/A" ]; then | |
nvm install | |
elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then | |
nvm use --silent | |
fi | |
elif [ -n "$(PWD=$OLDPWD nvm_find_nvmrc)" ] && [ "$(nvm version)" != "$(nvm version default)" ]; then | |
echo "Reverting to nvm default version" | |
nvm use default --silent | |
fi | |
} | |
add-zsh-hook chpwd load-nvmrc | |
load-nvmrc | |
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! | |
export SDKMAN_DIR="$HOME/.sdkman" | |
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh" | |
$(startShutdownServerIdempotent > /dev/null 2>&1 &) | |
export PATH="$HOME/.cargo/bin:$PATH" # for Rust | |
## ================== OWN scripts | |
# git highlight | |
# gitify_prompt() | |
custom_prompt | |
# copy and paste - xclip/pb* | |
copyAndPaste | |
$(startShutdownServerIdempotent > /dev/null 2>&1 &) |
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
.DS_Store | |
.vscode/ |
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 sh | |
# CUSTOM Aliases ##################### | |
## https://apple.stackexchange.com/a/343629/458488 | |
alias afk="osascript -e 'tell application \"System Events\" to keystroke \"q\" using {command down,control down}'" | |
#ls | |
# alias l='ls -lah --color' | |
# alias ls='ls --color' | |
# git | |
alias gco="git checkout" | |
alias ga="git add" | |
alias gunadd="git restore --staged" # Unstage path1 path2... | |
alias gcan="git commit --amend --no-edit" | |
alias gcm="git commit -m" | |
function gcmp() { # git commit and push | |
gcm "$@" | |
git push | |
} | |
alias gst="git status" | |
alias gpp="git push" | |
alias gpl="git pull" | |
alias gls="git branch --sort=-committerdate" # git branch ls | |
function gplo() { | |
# `git pull other` branch | |
# for hands free other-than-current-branch-update, see https://stackoverflow.com/a/45622872 | |
# Assumption: remote and local branches have same name | |
# Todo, figure out remote branch name even if different and pull, so command always succeeds | |
# suppose you are on feat/xyz | |
# gplo staging # will update the staging | |
local_branch="$1" | |
remote_branch="origin/$1" | |
if [[ "$(git rev-parse --abbrev-ref $remote_branch)" == "origin/$local_branch" ]]; then | |
# Perform the pull operation | |
git fetch -u origin "$local_branch":"$local_branch" | |
else | |
echo "Error: Remote branch '$remote_branch' doesn't match local branch '$local_branch'" | |
echo "No action performed." | |
fi | |
} | |
function gsave() { | |
git stash save $@ | |
} | |
function gload() { | |
git stash apply "stash^{/$@}" | |
} | |
_gitstash_autocomplete() { | |
local cur | |
cur="${COMP_WORDS[COMP_CWORD]}" | |
COMPREPLY=( $(git stash list | sed -nE 's/stash@\{[0-9]+\}: (.*)/\1/p' | grep -i -- "$cur") ) | |
} | |
complete -F _gitstash_autocomplete gload | |
complete -F _gitstash_autocomplete gsave | |
# gh - GitHub CLI | |
# get "commit" link instead of "tree" link. | |
alias ghcc='gh browse --no-browser $(git rev-parse HEAD) --repo $(git remote get-url origin | sed -e "s#.*github.com[:/]\(.*\)\.git#\1#") | tr -d "\n"' | |
# See: https://github.com/cli/cli/issues/7502 | |
# Note: the --repo option is needed since `gh` doesn't work well when the repo is part of a fork chain | |
# the `git remote get-url` with `sed` is needed to get the value for `--repo`. `gh` doesn't have a way to get the repo name, yes, weird. | |
# the `git remote get-url` with `sed` works in all cases - cloned with git (SSH, HTTPS) or with `gh repo clone` | |
# CUSTOM Functions ##################### | |
poweroff() { | |
osascript -e 'tell app "System Events" to shut down' | |
} | |
# print (-s option) or navigate to Git repo root, current location or specified one | |
function groot { | |
local show= | |
local path= | |
# Parse command line options | |
while [[ $# -gt 0 ]]; do | |
case "$1" in | |
-s) | |
show=true | |
shift | |
;; | |
*) | |
path="$1" | |
shift | |
;; | |
esac | |
done | |
# If no path is specified, use the current directory | |
if [[ -z "$path" ]]; then | |
path="." | |
fi | |
# Get the Git root directory and either change to it or print it | |
local dir="$(cd "$path" && git rev-parse --show-toplevel 2>/dev/null)" | |
if [[ -n "$dir" ]]; then | |
dir="$(echo "$dir" | tr -d '\n')" | |
if [[ -n "$show" ]]; then | |
echo "$dir" | |
else | |
cd "$dir" || return | |
fi | |
else | |
echo "Not inside a Git repository" >&2 | |
return 1 | |
fi | |
} | |
# print random human-friendly name | |
function namegen { | |
jsCode=$(cat <<-ENDJS | |
const { | |
uniqueNamesGenerator, | |
adjectives, | |
colors, | |
animals | |
} = require('unique-names-generator'); | |
const output = uniqueNamesGenerator({ | |
dictionaries: [adjectives, colors, animals], | |
separator: '-' | |
}); | |
console.log(output); | |
ENDJS | |
) | |
node -e "$jsCode" | |
# npm package - https://www.npmjs.com/package/unique-names-generator#user-content-usage | |
# multiline bash - "here document" (chatGPT) - https://chat.openai.com/chat/21ad89f6-231f-4f92-8256-52c0f652fdcb | |
# node -e "some js code" option is available | |
} | |
function slow() { | |
# default waiting time | |
wait_time=0.5 | |
if [ "$1" -lt 5 ]; then | |
wait_time="$1" | |
return | |
fi | |
# if [ "$2" != '' ]; then | |
# $wait_time=$2 | |
# fi | |
# do the work using awk | |
"$@" | awk '{system("sleep '$wait_time'");print}' | |
} | |
function youtube-dl-numbered() { | |
# runs the alias | |
youtube-dl -cio "%(playlist_index)02d: %(title)s.%(ext)s" --write-sub --write-auto-sub --sub-lang en --embed-subs "$@" | |
} | |
function reposize() { | |
# https://webapps.stackexchange.com/questions/39587/view-estimated-size-of-github-repository-before-cloning | |
printf "$1" | perl -ne 'print $1 if m!([^/]+/[^/]+?)(?:\.git)?$!' | xargs -i curl -s -k https://api.github.com/repos/'{}' | grep size | tr -d -c 0-9 | awk '{printf $1/1024}' | |
echo " MB" | |
} | |
#advanced grep - works for images and pdfs too | |
function advgrep() { | |
grep "$1" -ri -I # text files | |
pdfgrep "$1" -ri # PDFs | |
# images | |
GRAY='\033[1;32m' | |
NC='\033[0m' # No Color | |
for file in $(find . -name '*.*g'); do | |
tesseract "$file" stdout 2>/dev/null | grep "$1" -i && echo -e "${GRAY}$file${NC}\n" | |
done | |
} | |
function custom_prompt() | |
{ | |
export GIT_PS1_SHOWDIRTYSTATE=1 | |
PS1='%B%F{green}sanjar%f%b$%F{red} %c%f ' | |
# if [[ "${USERNAME}" == "muhammadsanjar"]] then | |
# PS1='%B%F{green}sanjar%f%b$%F{red}%~%f ' | |
# else | |
# # use $USERNAME | |
# PS1='%B%F{green}%n%f%b$%F{red}%~%f ' | |
# fi | |
} | |
# gitify prompt, taken from the Udacity Git course | |
function gitify_prompt() { | |
red="\[\033[38;5;203m\]" | |
green="\[\033[38;05;38m\]" | |
blue="\[\033[0;34m\]" | |
reset="\[\033[0m\]" | |
export GIT_PS1_SHOWDIRTYSTATE=1 | |
# '\u' adds the name of the current user to the prompt | |
# '\$(__git_ps1)' adds git-related stuff | |
# '\W' adds the name of the current directory | |
export PS1="$red\u$green\ $(__git_ps1)$blue \W | |
$ $reset" | |
# Changes colors for tty consoles | |
if [ "$TERM" = "xterm-256color" ]; then | |
echo -en "\e]P0232323" #black | |
echo -en "\e]P82B2B2B" #darkgrey | |
echo -en "\e]P1D75F5F" #darkred | |
echo -en "\e]P9E33636" #red | |
echo -en "\e]P287AF5F" #darkgreen | |
echo -en "\e]PA98E34D" #green | |
echo -en "\e]P3D7AF87" #brown | |
echo -en "\e]PBFFD75F" #yellow | |
echo -en "\e]P48787AF" #darkblue | |
echo -en "\e]PC7373C9" #blue | |
echo -en "\e]P5BD53A5" #darkmagenta | |
echo -en "\e]PDD633B2" #magenta | |
echo -en "\e]P65FAFAF" #darkcyan | |
echo -en "\e]PE44C9C9" #cyan | |
echo -en "\e]P7E5E5E5" #lightgrey | |
echo -en "\e]PFFFFFFF" #white | |
clear #for background artifacting | |
fi | |
} | |
# To use the Heroku CLI's autocomplete -- | |
# Via homebrew's shell completion: | |
# 1) Follow homebrew's install instructions https://docs.brew.sh/Shell-Completion | |
# NOTE: For zsh, as the instructions mention, be sure compinit is autoloaded | |
# and called, either explicitly or via a framework like oh-my-zsh. | |
# 2) Then run | |
# $ heroku autocomplete --refresh-cache | |
# OR | |
# Use our standalone setup: | |
# 1) Run and follow the install steps: | |
# $ heroku autocomplete | |
# CLI clipboard copy, paste | |
# Usage: `someCommand | c` copies the output to the clipboard | |
# Examples: `ls | c`, `cat someFile.txt | c`, `cat someFile.txt | grep 'hello' | c` | |
function copyAndPaste() { | |
if command -v xclip &> /dev/null | |
then | |
alias c="xclip -selection clipboard" | |
alias v="xclip -o -selection clipboard" | |
# echo "xclip exists" | |
return | |
fi | |
if command -v pbcopy &> /dev/null | |
then | |
alias c="cat | pbcopy" | |
alias p="pbpaste" | |
# echo "pbcopy exists" | |
return | |
fi | |
} | |
# kill process at port | |
# Usage: | |
# `portkill 3000` | |
# `portkill 8301 8302` (multiple arguments supported) | |
portkill() { | |
for port in "$@"; do | |
pids=$(lsof -ti tcp:"$port") | |
if [ -n "$pids" ]; then | |
echo "Killing process using port $port" | |
echo "$pids" | xargs kill | |
else | |
echo "No processes found using port $port." | |
fi | |
done | |
} | |
# print total number of lines in files at path and all descendants | |
function countLines() { | |
find "$1" -type f -exec wc -l {} + | awk '{total += $1} END{print total}' | |
} | |
## bookmark setup for paths, START | |
## https://github.com/sanjar-notes/swe-culture-n-tools/issues/12 | |
## source: https://jeroenjanssens.com/navigate/ | |
export MARKPATH=$HOME/.marks | |
function jump { | |
cd -P "$MARKPATH/$1" 2>/dev/null || echo "No such mark: $1" | |
} | |
function mark { | |
mkdir -p "$MARKPATH"; ln -s "$(pwd)" "$MARKPATH/$1" | |
} | |
function unmark { | |
rm -i "$MARKPATH/$1" | |
} | |
function marks { | |
\ls -l "$MARKPATH" | tail -n +2 | sed 's/ / /g' | cut -d' ' -f9- | awk -F ' -> ' '{printf "%-10s -> %s\n", $1, $2}' | |
} | |
function getmark { | |
echo $(realpath "$MARKPATH/$1") || echo "No such mark: $1" | |
} | |
function remark { | |
unmark "$1" | |
mark "$1" | |
} | |
function _completemarks { | |
reply=($(ls $MARKPATH)) | |
} | |
compctl -K _completemarks jump | |
compctl -K _completemarks unmark | |
compctl -K _completemarks remark | |
compctl -K _completemarks getmark | |
# make shorter aliases for these | |
alias jp="jump" | |
alias mk="mark" | |
alias um="unmark" | |
alias mks="marks" | |
alias gm="getmark" | |
## bookmark setup END | |
# import function (run all top level files at path) | |
run_files_in_dir() { | |
local directory="$1" | |
if [ -d "$directory" ]; then | |
for file in "$directory"/*.sh; do | |
[ -e "$file" ] && source "$file" | |
done | |
else | |
# commented out - remains silent | |
# echo "Error: Directory not found - $directory" | |
: | |
fi | |
} | |
urlencode() { | |
local l=${#1} | |
for (( i = 0 ; i < l ; i++ )); do | |
local c=${1:i:1} | |
case "$c" in | |
[a-zA-Z0-9.~_-]) printf "$c" ;; | |
' ') printf + ;; | |
*) printf '%%%.2X' "'$c" | |
esac | |
done | |
} | |
urldecode() { | |
local data=${1//+/ } | |
printf '%b' "${data//%/\x}" | |
} | |
# usage | |
# obsidian path-to-vault | |
# obsidian path-to-vault note_path | |
# obsidian . | |
obsidian() { | |
value_git_based_name=$(basename $(cd $1; git root)) | |
value_current_dir_based_name=$(basename "$(realpath $1)") | |
vault_value=$([[ -z "$value_git_based_name" ]] && echo $value_current_dir_based_name || echo $value_git_based_name) | |
file_part=$([[ -z "$2" ]] && echo "" || "&file=$(urlencode $2)") | |
# echo "value_git_based_name:$value_git_based_name value_current_dir_based_name:$value_current_dir_based_name vault_value:$vault_value file_part$file_part" | |
open "obsidian://open?vault=$vault_value$file_part" # >/dev/null 2>&1 & #doesn't need it | |
} | |
# https://www.notion.so/sanjarcode/Serialize-Git-commits-for-storing-notes-procedures-10c20b93200480a4aa65f0ab22c7e2ac?pvs=4 | |
# Example: `generate_patch` (patches w.r.t main) | |
# Example: `generate_patch parent-branch-name` (patches w.r.t parent-branch-name) | |
generate_patch() { | |
local parent_branch="${1:-main}" # Default to 'main' if no argument is given | |
local current_branch=$(git rev-parse --abbrev-ref HEAD) # Get the current branch name | |
# Replace slashes with hyphens | |
current_branch="${current_branch//\//-}" | |
local patch_file="${current_branch}.patch" # Name the patch file after the current branch | |
# Get the base commit from the parent branch | |
local base_commit | |
base_commit=$(git merge-base "$parent_branch" HEAD) | |
# Generate the patch | |
git log -p "$base_commit..HEAD" -- ':!./*lock*' > "$patch_file" | |
echo "Patch generated: $patch_file" | |
} | |
_generate_patch() { | |
local branches | |
branches=$(git branch --format='%(refname:short)') # Get all branches | |
COMPREPLY=($(compgen -W "$branches" -- "${COMP_WORDS[1]}")) # Complete based on branches | |
} | |
complete -F _generate_patch generate_patch | |
# safely add my scripts, for home-controller | |
run_files_in_dir ~/.my-scripts /dev/null 2>&1 | |
$(startShutdownServerIdempotent > /dev/null 2>&1 &) |
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
export PATH="$PATH:/opt/homebrew/bin/" | |
export PATH="$PATH:/opt/homebrew/lib/ruby/gems/3.0.0/bin" | |
export NVM_DIR="$HOME/.nvm" | |
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm | |
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion | |
# enable global 3rd party modules import - added by me | |
# CommonJS syntax works, ESM gives error (partially) | |
if [ -n "$NVM_BIN" ]; then | |
export NODE_PATH="${NVM_BIN/bin/lib/node_modules}" | |
export PATH="$PATH:$NODE_PATH" | |
else | |
___MYNODEPATH=$(npm root -g 2> /dev/null) | |
if [ -n "___MYNODEPATH" ]; then | |
export NODE_PATH=$___MYNODEPATH | |
export PATH="$PATH:$NODE_PATH" | |
fi | |
fi | |
# Alias definitions. | |
# You may want to put all your additions into a separate file like | |
# ~/.zsh_aliases, instead of adding them here directly. | |
if [ -f ~/.zsh_aliases ]; then | |
. ~/.zsh_aliases | |
fi | |
#Added manually, during pyenv installation | |
if [ -f ~/.zprofile ]; then | |
. ~/.zprofile | |
fi | |
## ================== Post install variables | |
if type pyenv &>/dev/null; then | |
eval "$(pyenv init -)" | |
fi | |
if type rbenv &>/dev/null; then | |
eval "$(rbenv init -)" # rbenv, added manually | |
fi | |
if type brew &>/dev/null; then | |
FPATH=$(brew --prefix)/share/zsh-completions:$FPATH | |
autoload -Uz compinit | |
fi | |
# Added after Rosetta 2 install | |
# alias rbrew='/usr/local/bin/brew' | |
# # Rosetta brew | |
# % which rbrew | |
alias rbrew="/usr/local/bin/brew" | |
# # Native brew | |
# % which brew | |
# /opt/homebrew/bin/brew | |
export PATH="/opt/homebrew/opt/libpq/bin:$PATH" | |
export PATH="/usr/local/bin:/usr/local/sbin:~/bin:$PATH" # for brew path $ | |
# https://stackoverflow.com/q/12861422 --> https://stackoverflow.com/a/11$ | |
export HOMEBREW_NO_AUTO_UPDATE=1 # disable auto update on each run of brew | |
# AndroidStudio \w React Native setup docs | |
export ANDROID_SDK_ROOT=$HOME/.devTools/Android/Sdk | |
export PATH=$PATH:$ANDROID_SDK_ROOT/emulator | |
export PATH=$PATH:$ANDROID_SDK_ROOT/platform-tools | |
export PATH=~/Library/Android/sdk/tools:$PATH | |
export PATH=~/Library/Android/sdk/platform-tools:$PATH | |
# pnpm | |
export PNPM_HOME=$HOME/Library/pnpm | |
case ":$PATH:" in | |
*":$PNPM_HOME:"*) ;; | |
*) export PATH="$PNPM_HOME:$PATH" ;; | |
esac | |
# pnpm end | |
# place this after nvm initialization! | |
autoload -U add-zsh-hook | |
load-nvmrc() { | |
local nvmrc_path | |
nvmrc_path="$(nvm_find_nvmrc)" | |
if [ -n "$nvmrc_path" ]; then | |
local nvmrc_node_version | |
nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")") | |
if [ "$nvmrc_node_version" = "N/A" ]; then | |
nvm install | |
elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then | |
nvm use --silent | |
fi | |
elif [ -n "$(PWD=$OLDPWD nvm_find_nvmrc)" ] && [ "$(nvm version)" != "$(nvm version default)" ]; then | |
echo "Reverting to nvm default version" | |
nvm use default --silent | |
fi | |
} | |
add-zsh-hook chpwd load-nvmrc | |
load-nvmrc | |
#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!! | |
export SDKMAN_DIR="$HOME/.sdkman" | |
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh" | |
export PATH="$HOME/.cargo/bin:$PATH" # for Rust | |
test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh" | |
# cocaopods | |
# export GEM_HOME=$HOME/.gem | |
# export PATH=$GEM_HOME/bin:$PATH | |
## ================== OWN scripts | |
# git highlight | |
# gitify_prompt() | |
custom_prompt | |
# copy and paste - xclip/pb* | |
copyAndPaste | |
export PATH="$HOME/.cargo/bin:$PATH" # for Rust | |
export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH" # postgres | |
plugins=(git zsh-autosuggestions) # https://catalins.tech/zsh-plugins/#:~:text=2.%20Zsh--,autosuggestions%20plugin,-You%20most%20likely | |
$(startShutdownServerIdempotent > /dev/null 2>&1 &) |
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 sh | |
# Recursively process directories and move files with the same name as | |
# their parent folder to be inside that folder with the name | |
FilesNameAsFolder_moveFilesToFolderAsIndex() { | |
local location="${1:-$(pwd)}" # Get the directory location from the argument | |
shopt -s globstar | |
for file in "$location"/**/*.md; do | |
if [[ -f $file ]]; then | |
dir=$(dirname "$file") | |
filename=$(basename "$file") | |
filename_no_ext="${filename%.*}" | |
if [[ -d "$dir/$filename_no_ext" ]]; then | |
echo "File $file has been moved" | |
mv "$file" "$dir/$filename_no_ext/0_index.md" | |
# # for debug | |
# else | |
# echo "$file is OK" | |
fi | |
fi | |
done | |
} | |
# Call the function and pass the directory location as an argument | |
# FilesNameAsFolder_moveFilesToFolderAsIndex . | |
## Handle blanks | |
# check if file's last non-empty line starts with just "Created" | |
# essentially checking if it's an empty file | |
Blanks_fileHasCreated() { | |
local file="$1" | |
local second_line=$(awk 'NF && ++c==2 && tolower($0) ~ /^created /' "$file") | |
local last_line=$(awk 'NF{a=$0}END{print a}' "$file") | |
if [[ -n "$second_line" && "$second_line" == "$last_line" ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
# Blanks_fileHasCreated_test path-to-location | |
Blanks_fileHasCreated_test() { | |
local location="$1" # Get the directory location from the argument | |
shopt -s globstar | |
for file in "$location"/**/*.md; do | |
if [[ -f $file ]]; then | |
if Blanks_fileHasCreated "$file"; then | |
echo "File $file has 'Created' in the second line." | |
else | |
echo "File $file does not meet the condition." | |
fi | |
fi | |
done | |
} | |
# Blanks_deleteFilesThatHaveCreatedTextOnly path-to-location | |
Blanks_deleteFilesThatHaveCreatedTextOnly() { | |
local location="${1:-$(pwd)}" # Get the directory location from the argument | |
shopt -s globstar | |
for file in "$location"/**/*.md; do | |
if [[ -f $file ]]; then | |
if Blanks_fileHasCreated "$file"; then | |
rm "$file" | |
echo "File $file deleted." | |
fi | |
fi | |
done | |
} | |
# Blanks_deleteFilesThatHaveCreatedTextOnly | |
# A function that deletes empty folders and files, recursively given location | |
childDirs() { | |
local location="${1:-$(pwd)}" | |
find "$location" -mindepth 1 -maxdepth 1 -type d -exec sh -c ' | |
for dir do | |
if [ "$dir" != "$location/." ]; then | |
echo "$dir" | sed "s#/\$##" | |
fi | |
done' sh {} + | |
} | |
# cleanEmptyFolders path | |
# cleanEmptyFolders path --hidden | |
cleanEmptyFolders() { | |
local _location="${1:-$(pwd)}" | |
local _hidden="${2}" | |
local dir | |
for dir in $(childDirs "$_location"); do | |
# $_hidden | |
if [[ ! $_hidden == "--hidden" && $(basename "$dir") == .* ]]; then | |
# echo "Skipping hidden folder: $dir" | |
continue # Ignoring hidden folders | |
fi | |
# echo "Dir: $dir" | |
# echo "Exploring: $dir" | |
cleanEmptyFolders "$dir" "$_hidden" | |
if [[ ! $(ls -A "$dir") ]]; then | |
# echo "After check dir: $dir" | |
rmdir "$dir" | |
echo "Empty folder '$dir' deleted." | |
fi | |
done | |
} |
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 sh | |
# placed at ~/.my-scripts | |
# Main commands: hc_setup, hc, hc_f, hc_l | |
# link: https://github.com/exemplar-codes/arduino-nodemcu-board-code/tree/c4b95283333af8876ec6b76a5306003b35e42d6c/nodemcu/POST_polling_relay_control_nodemcu | |
# discovers and prints result, or empty | |
_discover_url() { | |
DEBUG_MODE="" # false | |
# DEBUG_MODE="x" # true | |
url="" | |
for i in {0..9}; do | |
url="http://192.168.0.10$i:4000" | |
# curl $url -m 1 >/dev/null 2>&1 | |
# curl $url -m 1 | |
if [ -n "${DEBUG_MODE}" ]; then | |
curl -w '\n' $url -m 1 | |
else | |
curl -w '\n' $url -m 1 >/dev/null 2>&1 | |
fi | |
if [ $? -eq 0 ]; then | |
break | |
fi | |
if [ -n "${DEBUG_MODE}" ]; then | |
echo "FAIL: $url" | |
echo $? | |
echo "---\n" | |
fi | |
url="" # clear value since it's invalid | |
done | |
echo $url | |
} | |
# discovers, stores url in file | |
hc_setup() { | |
echo $(_discover_url) >~/.hc_url | |
# echo "http://192.168.0.103:4000" >~/.hc_url | |
} | |
# get stored URL | |
hc_url() { | |
cat ~/.hc_url | |
} | |
hc() { | |
stored_url=$(hc_url) | |
echo $stored_url | |
curl -w '\n' $stored_url | |
} | |
hc_f() { | |
url="$(hc_url)/toggle/0" | |
echo $url | |
curl -w '\n' $url | |
} | |
hc_l() { | |
url="$(hc_url)/toggle/1" | |
echo $url | |
curl -w '\n' $url | |
} |
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 sh | |
# Function to keep the connection alive | |
keep_alive() { | |
# Define a hidden lock file | |
local LOCK_FILE="$HOME/.keep_alive.lock" | |
# Check if the lock file exists | |
if [ -f "$LOCK_FILE" ]; then | |
echo "Another instance of keep_alive is already running." | |
return 1 | |
fi | |
# Create the lock file | |
touch "$LOCK_FILE" | |
# Ensure the lock file is removed when the script exits | |
trap "rm -f $LOCK_FILE" EXIT | |
echo "Starting keep_alive function..." | |
# Loop to send ping requests | |
while true; do | |
ping -c 1 8.8.8.8 > /dev/null | |
sleep 60 | |
done | |
} |
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 sh | |
# y/n confirmation | |
# usage: `confirm "Show files" && ls` | |
confirm() { | |
local prompt="$1" | |
local response | |
# Prompt the user until a valid response is received | |
while true; do | |
echo -n "$prompt (y/n): " | |
read response | |
case "$response" in | |
[yY][eE][sS] | [yY]) | |
return 0 # Success | |
;; | |
[nN][oO] | [nN]) | |
return 1 # Error | |
;; | |
*) | |
echo "Please answer 'yes' or 'no'." | |
;; | |
esac | |
done | |
} | |
## Use LLM to generate commands to be run in terminal | |
## `llm` set up: https://github.com/simonw/llm#installation | |
## Multi line responses if given by the LLM work just fine (example - bash function definition) | |
# Usage: | |
# First step: Run `source llm_stuff.sh` | |
# Second step: Run `aido "print hello"` | |
# this will show a command to be run in the terminal, and prompt the user to confirm | |
# note: have to do manual source since `llm` command isn't available when `.bashrc` is initialized. will solve this later. | |
## Realistic example (below) | |
# aido "show non-hidden files greater than 1kb in current folder" | |
# Generated Command: ls -l | grep -v "^d" | awk '$5 > 1' | |
# Do you want to execute the generated command (y/n): y | |
# -rw-r--r--@ 1 muhammad staff 1338 Oct 15 18:56 home-controller.sh | |
# -rw-r--r--@ 1 muhammad staff 1372 Oct 24 19:54 llm_stuff.sh | |
# -rw-r--r--@ 1 muhammad staff 507 Oct 24 19:44 utils.sh | |
aido() { | |
# Check if a command is provided | |
if [ -z "$1" ]; then | |
echo "Usage: aido <command>" | |
return | |
fi | |
# Create a template for the llm command with proper escaping | |
template="write a command to $1, in current folder on linux. Only write the command/code, no explanation is needed" | |
# Use the `llm` command to get the language model response using the template | |
llm_response=$(llm "$template") | |
# Print the generated command from the language model | |
echo "Generated Command: $llm_response" | |
# Prompt the user if they want to execute the generated command | |
confirm "Do you want to execute the generated command" || { | |
echo "No command run" | |
return | |
} | |
# Execute the generated command | |
eval "$llm_response" | |
} |
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 sh | |
# Note: The process takes ~1 minutes (best) | |
# Script level usage | |
### Requirements | |
## 1. Need an Expo account. | |
## 2. Install EAS CLI. Install using `npm install -g eas-cli` | |
## 3. Install project dependencies, `npm install` | |
# Running the script | |
## Step 1: Run this script `source ~/path-to/MAD.sh` | |
## Step 2: Go to your expo project. | |
## Step 3: Run `build_apk` in the terminal. | |
## Step 4: Log in with Expo credentials if needed, and answer the prompts (or just press enter). | |
## Done! | |
## APK will be generated named `build-171something.apk` | |
build_apk() { | |
build_aab | |
aab_to_apk | |
} | |
## expo project to AAB | |
build_aab() { | |
eas build --platform android --local | |
} | |
## AAB to APK | |
## Assumes defaults for input and output directory (same a project) | |
## provides device-spec.json file if not specified | |
## you don't need eas.json, it's generated automatically while generating AAB | |
aab_to_apk() { | |
# Search for bundletool*.jar in ~/Downloads | |
BUNDLETOOL_JAR=$(find ~/Downloads -name "bundletool*.jar" -type f -print -quit) | |
# Default AAB path (latest AAB in current directory if not provided) | |
AAB_PATH="${1:-$(find . -maxdepth 1 -type f -name "*.aab" -print -quit)}" | |
# Default output directory (current directory if not provided) | |
OUTPUT_DIR="${2:-.}" | |
# Default device spec path (./device-spec.json if not provided) | |
DEVICE_SPEC="${3:-}" | |
# Default device spec content | |
DEFAULT_DEVICE_SPEC='{ | |
"supportedAbis": ["arm64-v8a", "armeabi-v7a"], | |
"screenDensity": 420, | |
"sdkVersion": 28, | |
"supportedLocales": ["en-US", "es-ES"] | |
}' | |
# Use default device spec if not provided | |
if [ -z "$DEVICE_SPEC" ]; then | |
DEVICE_SPEC="./device-spec.json" | |
echo "$DEFAULT_DEVICE_SPEC" > "$DEVICE_SPEC" | |
fi | |
# Extract AAB file name without extension | |
AAB_FILE_NAME=$(basename -- "$AAB_PATH") | |
AAB_FILE_NAME="${AAB_FILE_NAME%.*}" | |
# Check if all required arguments are provided | |
if [ -z "$BUNDLETOOL_JAR" ] || [ -z "$AAB_PATH" ] || [ -z "$OUTPUT_DIR" ] || [ -z "$DEVICE_SPEC" ]; then | |
echo "Usage: build_apk [<path/to/app.aab>] [<path/to/output/directory>] [<path/to/device-spec.json>]" | |
return 1 | |
fi | |
# Build APKs using bundletool | |
MODE="universal" | |
java -jar "$BUNDLETOOL_JAR" build-apks --bundle="$AAB_PATH" --output="$OUTPUT_DIR/app.apks" --mode="$MODE" | |
# Extract APK from APKS | |
java -jar "$BUNDLETOOL_JAR" extract-apks --apks="$OUTPUT_DIR/app.apks" --output-dir="$OUTPUT_DIR" --device-spec="$DEVICE_SPEC" | |
rm "$OUTPUT_DIR/app.apks" # avoid already exists error on next run | |
## Copy the first APK to the current directory | |
generated_apk="$MODE.apk" | |
cp "$generated_apk" "./$AAB_FILE_NAME.apk" | |
rm "$OUTPUT_DIR/$generated_apk" | |
echo "APK copied successfully: $AAB_FILE_NAME.apk" | |
} | |
# Why this? Because `expo prebuild` is not working for me. Tried `https://github.com/expo/eas-cli/issues/1300#issuecomment-1834275766` | |
# Exact code I ran: `npx expo prebuild --platform android && cd android && ./gradlew assembleRelease` | |
# Turns out EAS build is new way to build on Expo, and prebuild is a legacy way to build. |
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 sh | |
PORT=4001 | |
# shut down computer when pinged, if locked, from any home device | |
# intent: preserve monitor from overheating | |
# setup: add as computer startup script | |
# works on macos, linux | |
function startShutdownServer() { | |
hc_path=$(getmark hc) | |
hc_script_path="$hc_path/app.js" | |
PORT="${PORT}" node $hc_script_path | |
} | |
function getProblematicPids() { | |
# hcpid=$(lsof -i -P -n | grep 4001 | awk '{print $2}') | |
# not needed, background jobs cannot affect shutdown | |
PROMPT_EOL_MARK='' # removes zsh's stupid EOL | |
pgrep -i -a 'iterm|qemu' | tr '\n' ' ' | |
} | |
function startShutdownServerIdempotent() { | |
# Check if localhost:4001 is reachable | |
isServerRunning=$(curl -sSf "http://localhost:${PORT}" > /dev/null 2>&1) | |
if [ $? != 0 ]; then | |
startShutdownServer > /dev/null 2>&1 & | |
else | |
# Echo a message indicating the server is already running | |
echo "Server already running on localhost:${PORT}" | |
fi | |
} | |
# Add to .zshrc | |
# $(startShutdownServerIdempotent > /dev/null 2>&1 &) |
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 sh | |
## Context: any-md is a directory with markdown files, I maintain on all devices | |
## It's bookmarked as any-md using the mark, getmark utility | |
TABLET_PATH="$(getmark any-md)/Excalidraw" | |
TABLET_FILE_NAME='drawing.excalidraw.md' | |
TABLET_PORT='4002' | |
TABLET_ADDRESS="http://192.168.0.101:$TABLET_PORT" | |
LAPTOP_PATH="$(getmark any-md)/Excalidraw" | |
LAPTOP_FILE_NAME='drawing.excalidraw.md' | |
# LAPTOP_PORT='4002' | |
# LAPTOP_ADDRESS="http://192.168.0.103:$LAPTOP_PORT" | |
FREQUENCY=1 # seconds | |
draw_laptop_sync_process() { | |
while true; do | |
FILENAME="$TABLET_ADDRESS/$TABLET_FILE_NAME" | |
URL="$LAPTOP_PATH/$LAPTOP_FILE_NAME" | |
curl -o "$URL" "$FILENAME" | |
sleep "$FREQUENCY" | |
done | |
} | |
draw_tablet_server() { | |
# check if command 'http-server' exists | |
if ! command -v http-server 2> /dev/null | |
then | |
echo "http-server could not be found" | |
confirm "Install it?" || { | |
echo "Not installed. Exiting." | |
return | |
} | |
fi | |
http-server "$TABLET_PATH" -p "$TABLET_PORT" | |
} |
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 sh | |
# y/n confirmation | |
# usage: `confirm "Show files" && ls` | |
## usage (with negatory hook), below | |
# confirm "Do you want to execute the generated command" || { | |
# echo "No command run" | |
# return | |
# } | |
## actual code | |
confirm() { | |
local prompt="$1" | |
local response | |
# Prompt the user until a valid response is received | |
while true; do | |
echo -n "$prompt (y/n): " | |
read response | |
case "$response" in | |
[yY][eE][sS] | [yY]) | |
return 0 # Success | |
;; | |
[nN][oO] | [nN]) | |
return 1 # Error | |
;; | |
*) | |
echo "Please answer 'yes' or 'no'." | |
;; | |
esac | |
done | |
} | |
## Create file at path if it doesn't exist | |
## meant especially for nested paths | |
## named after: `mkdir -p` | |
## Usage: `touchp A/B/C/nestedFile.md` | |
function touchp() { | |
local file_path=$1 | |
local dir_path=$(dirname "$file_path") | |
if [ ! -d "$dir_path" ]; then | |
mkdir -p "$dir_path" | |
fi | |
touch "$file_path" | |
} | |
# show all files at and under path, one per line | |
function show_files_tree() { | |
find . -type f | |
} | |
function ip_self_local() { | |
ifconfig 2> /dev/null | grep 'inet' | grep '192' | awk '/inet/ {print $2}' | |
} |
With regards to getting the repo name, gh repo view --json nameWithOwner -t '{{.nameWithOwner}}'
might do what you want if you selected origin
as the base repository.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Wow.. 😳. Thanks alot. Still learning but I'm a MARINE. I never give up.