Skip to content

Instantly share code, notes, and snippets.

@sanjarcode
Last active April 6, 2024 21:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sanjarcode/92aa6a164d16e51c343eed926047fb1f to your computer and use it in GitHub Desktop.
Save sanjarcode/92aa6a164d16e51c343eed926047fb1f to your computer and use it in GitHub Desktop.
Dotfiles - Linux, MacOS shell primer files - .bashrc and others
#!/usr/bin/env bash
# CUSTOM Aliases #####################
#ls
alias l='ls -lah --color'
alias ls='ls --color'
# git
alias g='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"
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
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
}
# 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 &
}
# safely add my scripts, for home-controller
run_files_in_dir ~/.my-scripts /dev/null 2>&1
$(startShutdownServerIdempotent > /dev/null 2>&1 &)
# ~/.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
### dev stuff
## 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
### custom stuff
# git highlight
gitify_prompt
# copy and paste - xclip/pb*
copyAndPaste
# 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
.DS_Store
.vscode/
#!/usr/bin/env sh
# CUSTOM Aliases #####################
#ls
# alias l='ls -lah --color'
# alias ls='ls --color'
# git
alias g='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"
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
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
}
# 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
}
# safely add my scripts, for home-controller
run_files_in_dir ~/.my-scripts /dev/null 2>&1
$(startShutdownServerIdempotent > /dev/null 2>&1 &)
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
# git highlight
# gitify_prompt()
custom_prompt
# copy and paste - xclip/pb*
copyAndPaste
if type pyenv &>/dev/null; then
eval "$(pyenv init -)"
fi
#postgreSQL
export PATH="/Applications/Postgres.app/Contents/Versions/13/bin:$PATH"
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
#!/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
}
#!/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
}
#!/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"
}
#!/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: Go to your expo project.
## Step 2: Run `build_apk` in the terminal.
## Step 3: 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.
#!/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 &)
#!/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"
}
#!/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}'
}
@ddasher654-we
Copy link

ddasher654-we commented May 31, 2023

Wow.. 😳. Thanks alot. Still learning but I'm a MARINE. I never give up.

@williammartin
Copy link

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