Tuesday, October 29, 2019

lsvideo - List Video Card/Driver Info

alias lsvideo='sudo $(type -P lspci) -vvvv -d "$($(type -P lspci) -nn|sed -n "/VGA/p"|$(type -P grep) -oP "(?<=\[)[[:alnum:]]{4}:[[:alnum:]]{4}(?=\])")"' 
Get the Latest onGitHub.

Saturday, October 26, 2019

exclude - Excludes Match & Optionally N-before / N-After - in Awk

alias exclude='_(){ local match="${1}";local lnb="${2}";local lnf="${3}"; (($#<1))||[[ "${1}" =~ ^- ]]&&echo "Usage: exclude <match> [<lines back [0-9],def=0> <lines forward [0-9],def=0>]"&&return 1;awk -vmtch="${match}" -vlnb=${lnb} -vlnf=${lnf} "BEGIN{i=0;skip=0}{if(skip==0 && \$0 ~ mtch){for(j=0;j<lnb&&i>0;j++)delete arr[--i];skip=lnf;}else{if(skip==0)arr[i++]=\$0;else skip--;}}END{for(i=0;i<length(arr);i++)print arr[i];}";};_' 
Get the latest on GitHub.

Friday, October 25, 2019

g2nasm - GAS ASM to NASM

Why didn't anyone else think to do this over the last 20+ years? I have no idea, but here it is. It's a Work In Progress, it's far from done but it's a decent start.
#!/bin/bash 
  ######################################################################
 ######################################################################
## Author: Adam Michael Danischewski 
## GitHub: https://github.com/AdamDanischewski/g2nasm
## Created Date: 2019-10-24
## Name: g2nasm.bsh 
## Version: v0.01
## Last Modified: 2019-10-24
## Issues: If you find any issues emai1 me at <my first name> (dot) 
##         <my last name> (at) gmail (dot) com. 
##
## Requirements: nasm, xxd, gnu awk, gnu sed
## 
## This script takes gas asm generated by gcc and converts it to nasm. 
## Eg. $> gcc -S -o code.gasm code.c 
## 
## You can then convert the code.gasm to nasm with this script: 
## Eg. $> g2nasm.bsh code.gasm > code.nasm 
##
## Then you can compile and run your nasm on Linux: 
## Eg. $> nasm -f elf64 -o code.o code.nasm 
##     $> gcc -no-pie -o run_code code.o 
##     $> ./run_code 
##
## As of this initial release it works for only a subset of gas asm - over 
## time this will hopefully work on all of gas asm (except prbly macros). 
## 
## For now this should work on simple programs. 
## Caveat: *** much is still missing/unmapped *** 
## Get the lastest on GitHub: https://github.com/AdamDanischewski/g2nasm 
## Pull requests invited. 
## 
## Tested on: 
## #include <stdio.h>
##
## /* function to show bytes in memory, from location start to start+n*/
## void show_mem_rep(char *start, int n)
## {
##     int i;
##     for (i = 0; i < n; i++)
##       printf(" %.2x", start[i]);
##     printf("\n");
## }
##   
## /*Main function to call above function for 0x01234567*/
## int main()
## {
##   int i = 0x01234567;
##   show_mem_rep((char *)&i, sizeof(i));
##   getchar();
##   return 0;
## }
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
##
## Released under Creative Commons License: CC BY-SA 4.0
## https://creativecommons.org/licenses/by-sa/4.0/
 ######################################################################
  ######################################################################
_=${BASH_ARGC} ### Cause BASH_ARGV to be populated, for options_handler. 

declare    FILE="${1}"
declare -a OPTIONS="" ## Used by: options_handler ()
declare    WORKING_COPY=""
declare -a GLOBALS 
declare    GLOBAL_OFFSET_TABLE_FLAG=0 
declare -r GLOBAL_OFFSET_TABLE="extern _GLOBAL_OFFSET_TABLE_" 
declare -a RO_BLOCKS
declare    RO_ALIGN="" 

function usage() {
cat << EOF 
Usage: ${0##*/} [-h] <file> 

 <file>: Gas asm file. 
         gcc -S -o code.gasm code.c ## file=code.gasm

 OPTIONS:
         -h|--help           Usage 
EOF
} 

function main_clean() { 
 WORKING_COPY=$(sed -E "/.string/!{s/, /,/g;s/%//g;s/\\$//g;s/je/jz/};/[ \t]*.(file|text|type|cfi_|size|ident|section|intel_syntax)/d;s/(^[ \t]*)(sub|lea|add|cmp|xor)([ql])([ \t]*)([^,]*)(,)([ \t]*)(.*$)/\1\2\4\8, \5/;s/\b(pop|push|sub|lea)([lq])\b/\1/;/^.LF..:/d" "${FILE}")
 GLOBALS[0]="$(sed -En 's/(^[ \t]*.globl)([ \t]*)([^ \t]*)(.*$)/global \3/p' <<< "${WORKING_COPY}")"
 WORKING_COPY=$(sed '/^[ \t]*.globl/d' <<< "${WORKING_COPY}")
 WORKING_COPY=$(sed -E '/\b[a-z]{3}q\b/s/(-[0-9]+)(\()([a-z]{3})(\))/qword [\3\1H]/' <<< "${WORKING_COPY}")
 WORKING_COPY=$(sed -E '/\b[a-z]{3}l\b/s/(-[0-9]+)(\()([a-z]{3})(\))/dword [\3\1H]/' <<< "${WORKING_COPY}")
 ## Every offset left except lea: -12(rbp)--> dword [rbp-0CH]
 WORKING_COPY=$(sed -E '/\blea\b/!s/(-[0-9]+)(\()([a-z]{3})(\))/dword [\3\1H]/' <<< "${WORKING_COPY}")
 ## lea mapping: -12(rbp)-->[rbp-0CH]
 WORKING_COPY=$(sed -E '/\blea\b/s/(-[0-9]+)(\()([a-z]{3})(\))/[\3\1H]/' <<< "${WORKING_COPY}")
}

function load_externals() { 
 local call="" 
 local plt="" 
 local -i i=0 
 while IFS= read -r call; do 
  let i+=1 
  call=$(awk '{print $2}' <<< "${call}")
  call="${call%@PLT}" 
  if ((! GLOBAL_OFFSET_TABLE_FLAG)); then 
   plt="${call##*@}"
   [[ -n "${plt}" ]] && GLOBAL_OFFSET_TABLE_FLAG=1
  fi 
  GLOBALS[${i}]="extern ${call}" 
 done < <(grep -P '^[ \t]*call' "${FILE}")
 WORKING_COPY="$(sed 's/@PLT//g' <<< "${WORKING_COPY}")"   
}

function num2hex() { printf "%02X\n" "${1}";}

function print_globals() { 
 local -i i=0
 for((i=0;i<${#GLOBALS[@]};i++)){ 
  printf "%11s\n" "${GLOBALS[${i}]}"
  ((i==0))&&echo
 }
 ((GLOBAL_OFFSET_TABLE_FLAG)) && printf "${GLOBAL_OFFSET_TABLE}\n"
 echo
}

function add_map() { 
 local -i line=0 
 local    val="" 
 local hexval="" 
 ## -8(rbp)-->[qd]word [rbp-8H]
}

function offset_to_hex() { 
 local -i line=0 
 local    val="" 
 local hexval="" 
 while IFS= read -r line; do 
  val="$(sed -nE "${line}s/(^[^0-9]+)([0-9]+H)(.*$)/\2/p" <<< "${WORKING_COPY}")"
  hexval=$(num2hex ${val%H})
  WORKING_COPY=$(sed "${line} s/${val}/${hexval}H/" <<< "${WORKING_COPY}")
 done < <(sed -nE '/^.*([dq]word|lea)[^0-9]*[0-9]+H.*$/=' <<< "${WORKING_COPY}") 
}

function mov_map() { 
 local -i line=0 
 local    val="" 
 local hexval="" 
 ## -8(rbp)-->qword [rbp-8H]
 WORKING_COPY=$(sed -E 's/(^[ \t]*)(mov)(sbl|zbl|slq|l|q)([ \t]*)([^,]*)(,)([ \t]*)(.*$)/\1\2\3\4\8, \5/' <<< "${WORKING_COPY}")
 WORKING_COPY=$(sed -E '/mov[dlq]/s//mov/;s/movzbl/movzx/g;s/movsbl/movsx/g;s/movslq/movsxd/g' <<< "${WORKING_COPY}")
}

function rax_map() { 
 WORKING_COPY=$(sed 's/(rax)/byte [rax]/g' <<< "${WORKING_COPY}")  
}

function leaq_map() { 
 ## .LC0(rip)-->[rel ?_001]
 ## --------------------------------------------------------------------------->> ## Make sure it's padded to three zeroes. 
 WORKING_COPY="$(sed -E '/.LC[0-9]/s/(\.LC)([0-9]+)(\()([a-z]{3})(\))/[rel ?_\2]/;s/(\[rel \?_)([0-9])]/\100\2]/;s/(\[rel \?_)([0-9][0-9])]/\10\2]/' <<< "${WORKING_COPY}")"
 ## Increment the label number. 
 WORKING_COPY="$(awk '{if($0 ~ /\[rel \?_[0-9]{3}/){match($0,/([0-9]{3})/,arr);var=arr[1]+1;var=sprintf("%03d",var);gsub(/[0-9]{3}/,var, $0); print $0;}else print;}' <<< "${WORKING_COPY}")"
}

## String Arg 1 - String to convert 
function convert_string_to_hex() {
 xxd -ps -c1 <(echo -en "${1}\x0"|sed 's/"//g')|tr '\n' ' '|sed -r 's/.{24}/\U&\n/g;s/^[ \t]*//'|sed -r '${s/^.*$/& 00 00 00 00 00 00 00 00 00/;s/^(.{24})(.*$)/\1/;};s/  / /g;s/^.*$/\U&/'| 
 sed -r 's/^./db &/;s/[0-9A-F]{2}[ \t]*$/&H/;s/[0-9A-F]{2}/&H,/g;'| sed -r 's/,[ \t]*$//;s/^.*$/        &/;s/0AH[ \t]*$/00H/;s/[,H \t]*$/H/'
}

## Load Read Only Blocks 
function get_ro_blocks() { 
 local block_start_addr=""
 local block_end_addr=""
 local block="" 
 local string="" 
 local ro_align="" 
 local -i ro_block_index=${#RO_BLOCKS[@]}
 ## get all read only block start addr's         
 while IFS= read -r block_start_addr; do 
  ## Note: start at index 1 since that's what nasm starts it's ro block labels at 
  let ro_block_index+=1
  ## save all read only blocks
  block="$(sed -En "${block_start_addr},/^[^ \t]/{/^[^ \t]/b;p}" <<< "${WORKING_COPY}")"
  block_end_addr="$(($(sed -En "$((${block_start_addr}+1)),\${/^[\.a-z]/{=;q}}" <<< "${WORKING_COPY}")-1))"
  WORKING_COPY="$(sed -E "${block_start_addr},${block_end_addr}s/^.*$/DELETE_THIS/" <<< "${WORKING_COPY}")"
  ro_align=$(sed -rn 's/^([ \t]*.align )([0-9]+)(.*$)/align=\2/p' <<< "${block}") 
  [[ -n "${ro_align}" ]] && RO_ALIGN="${ro_align}" && block="$(sed -r "s/.align[ \t]*[0-9]+//"<<<"${block}")" 
  string=$(sed -rn 's/^([ \t]*\.string)([ \t]*)("[^"]*")(.*$)/\3/p' <<< "${block}") 
  if [[ -n "${string}" ]]; then 
   string="$(convert_string_to_hex "${string}" | tr '\n' '\001')"
   block="$(sed -r "s/^[ \t]*\.string.*\$/${string}/;/^[ \t]*.(text|type|globl)/d" <<< "${block}"|tr '\001' '\n')" 
  fi  
  RO_BLOCKS[${ro_block_index}]="${block}"
 done < <(sed -En '/^\.LC[0-9]+:.*$/=' <<< "${WORKING_COPY}") 
 WORKING_COPY="$(sed '/^DELETE_THIS/d' <<< "${WORKING_COPY}")"
}

function print_ro_blocks() { 
 local -i i=1 
 printf "SECTION .rodata %s\n\n" "${RO_ALIGN}"
 for((i=1;i<=${#RO_BLOCKS[@]};i++)){ 
  printf "?_%03.f:\n" ${i}
  printf "%s\n" "${RO_BLOCKS[$i]}"
 }
}

function fs_map() { 
 ## fs:40-->qword [fs:abs 28H] 
WORKING_COPY="$(sed -E '/\bfs:[0-9]+\b/s/\bfs:([0-9]+)\b/qword [fs:abs \1H]/' <<< "${WORKING_COPY}")"
}

function init() { 
 main_clean
 load_externals
 get_ro_blocks
 mov_map
 leaq_map
 rax_map
 fs_map
 offset_to_hex ## Call this last. 
}

function print_section_text() { 
 printf "SECTION .text\n\n"
}

function print_section_data() { 
 printf "SECTION .data\n\n"
}

function print_section_bss() { 
 printf "SECTION .bss\n\n"
}

function main() { 
 init
 print_globals
 print_section_text
 printf "%s\n\n" "${WORKING_COPY}"
 print_section_data
 print_section_bss
 print_ro_blocks
}

function options_handler() { 
 local -i i=0
 local CURVAL=""
 local NEXTVAL=""
 ((${#BASH_ARGV[@]}==0)) && usage && exit 0 
 for((i=$((${#BASH_ARGV[@]}-1));i>=0;i--)); do 
  CURVAL=${BASH_ARGV[${i}]}
  NEXTVAL=${BASH_ARGV[$((${i}-1))]}
  case "${CURVAL}" in
      -h|-?|--help)
      usage 
      exit 0 
      ;; 
      *) 
      FILE="${CURVAL}"
      [[ ! -e "${FILE}" ]] && printf "*** ERROR - File (\"${FILE}\") not found. \n" && exit 1
      ;;
  esac
 done 
}

options_handler
main 
exit 0
Get the latest on GitHub.

gd / df Wrapper - Optionally Prints Device/Mount/Size for any File/Dir

Simple df -h wrapper that will show the /dev/ or /mnt/ point of any file/dir. It is scriptable and trims trailing @'s for those who like to visualize their links.
alias gd='_(){ local -i popts=0;[[ "${1}" =~ ^-[sS] ]]&&popts=1&&shift;[[ "${1}" =~ ^-[aA] ]]&&popts=2&&shift;[[ "${1}" =~ ^-[mM] ]]&&popts=3&&shift;local ref="${1%@}";if(($#<1))||[[ "${ref}" =~ ^- || ! -e "${ref}" ]];then echo "Usage: gd [[-s, print size] | [-a, print all] | [-m, print mount point]] <reference file/dir>, arg1=${1},arg2=${2}";[[ ! "${ref}" =~ ^- && ! -e "${ref}" && (($#>0))]]&&echo "*** gd::Error - File (\"${ref}\") not found.";return 1;fi;df -h "$(readlink -f "${ref}")"|awk -vpopts=${popts} "NR==1{header=\$0};NR>1{if(popts==1)print \$1,\$2;else if(popts==2){printf(\"%s\n%-16s%-6s%-5s%-6s%-5s%-20s\n\",header,\$1,\$2,\$3,\$4,\$5,\$6);}else if(popts==3)print \$6;else print \$1;}";};_' 
Get the latest on GitHub.

Tuesday, October 22, 2019

pnasm64 - Migrate C Code to NASM

Nasm is decently structured assembly - if you ever are interested in harnessing the true power of a new chipset you'll probably need to write assembly at some point.
alias pnasm64='_(){ local sel="";local file="${1}"; (($#<1))||[[ "${1}" =~ ^- || ! -e "${file}" ]]&&echo "Usage: pnasm64 <your.c> [-t (compile and link)]"&&return 1;rm -f "${file%.c}.o" "${file%.c}.asm";echo "Decompiling into object code.";gcc -fno-asynchronous-unwind-tables -s -c "${file}" -o "${file%.c}.o";echo "Converting to nasm.";objconv -fnasm "${file%.c}.o"; sed -i -e "s/align=1//g" -e "s/[a-z]*execute//g" -e "s/: *function//g" -e "/default *rel/d" "${file%.c}.asm";[[ -n "${2}" && "${2}" =~ "-t" ]]&&echo "Compiling with nasm..."&&nasm -felf64 -o "${file%.c}2.o" "${file%.c}.asm"&&echo "Linking with gcc..."&&gcc -fno-pie -no-pie -o "${file%.c}" "${file%.c}2.o";};_' 
To run this you'll need nasm, gcc from the repos - and objconv from: https://www.agner.org/optimize/
And this will only work out-of-the-box on simple C programs, to add libraries you'll need to hack it up and make it your own. Get the latest on GitHub.

Sunday, October 20, 2019

Tuesday, October 15, 2019

writes - Print HD Writes

The following alias prints HD writes for a hard drive in TB.
alias writes='_(){ (($#<1))||[[ "${1}" =~ ^- ]]&&echo "Usage: writes <drive eg. /dev/sdb>"&&return 1;local drive="${1}";[[ ! -e "${drive}" ]]&&echo "Device (${drive}) not found."&&return 1;smrt=$(sudo smartctl -a "${drive}");grep -iEq "unsupported"<<<"${smrt}"&&echo "Error: Not a smart tools capable SSD."&&return 1;sector_sz=$(awk "/^Sector Size:/{gsub(/[^0-9]/,\"\",\$3);print \$3}" <<< "${smrt}");lbas=$(awk "/Total_LBAs_Written/{print \$10}" <<< "${smrt}");if [[ -n "${lbas}" ]];then writes=$(echo "scale=10;(${lbas}*${sector_sz})/1099511627776"|bc);else giga=$(awk "/Lifetime_Writes_GiB/{print \$10}" <<< "${smrt}");if [[ -n "${giga}" ]];then writes=$(echo "scale=10;(${giga}*1.073741824)/1000"|bc);else tlc32=$(awk "/TLC_Writes_32MiB/{print \$10}" <<< "${smrt}");[[ -z ${tlc32} ]]&&echo "Error - Could not find write data for drive ($drive)."&&return 1;writes=$(echo "scale=10;((${tlc32}*32*1.073741824)/1000)/1000"|bc);fi;fi;printf "Total writes for drive %s: %.2f TB\n" ${drive} ${writes};};_' 
Get the lastest on GitHub

Tuesday, October 8, 2019

Terminal Color Analyzer - Prints True RGB Values for Terminal Colors

#!/bin/bash 

  ######################################################################
 ######################################################################
## Author: Adam Michael Danischewski 
## GitHub: https://github.com/AdamDanischewski/scriptsandoneliners
## Created Date: 2019-10-08
## Name: pscolors.bsh
## Version: v0.01
## Last Modified: 2019-10-08
## Issues: If you find any issues emai1 me at <my first name> (dot) 
##         <my last name> (at) gmail (dot) com. 
##
## Requirements:xdotool/xdotool, xwininfo/x11-utils, tput/ncurses-bin, 
##              scrot/scrot, convert/imagemagick 
## On Ubuntu: 
## sudo apt-get install xdotool x11-utils scrot ncurses-bin imagemagick
##
## Prints the full xterm-256 ansi color mapping to RGB (decimal) and HEX 
## in ANSI color (\x1b[38;5;<ansi>m) and Truecolor (\x1b[38;2;<R>;<G>;
## <B>m) and prints the rgb values of the colors that the terminal 
## prints to the screen. 
##
## How? First it prints all 256 ANSI colors for your terminal into a 
## grid then it uses scrot to take a screenshot. It then steps over the 
## image using imageMagick to pull the pixel color value for each cell. 
## 
## Why? Because there are alot of potential manipulators of color prior 
## to colors landing on the actual screen. E.g. compton, shading, etc.  
##
## With this tool you can get the end result rgb colors after all 
## graphics processing is done when you are looking at your terminal. 
## 
## Without this tool, you would only know what you configured and what 
## is advertised. This tool gives you the color actuals -- of course you 
## can't really SEE the actual colors though I attempt to display them 
## in TRUECOLOR. You can grab the RGB values and display them elsewhere 
## (e.g. color tool in a web browser) to really see the nuances between 
## what is advertised and what is experienced in your terminal.  
## 
## Note: If you have translucent windows, the background may affect the 
## results - you should probably kill conky and run this on a blank 
## workspace in a maximized terminal for best results. 
##
## Look-up values gleened from: 
## https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
##
## Released under Creative Commons License: CC BY-SA 4.0
## https://creativecommons.org/licenses/by-sa/4.0/
 ######################################################################
  ######################################################################

 ## Global variables 
declare    SCREENSHOT_LOC=/tmp/__pscolorscrnshot_$RANDOM__.png
declare -i COLOR_SWATCH_IMG_COLS=60 ## Use a 60 term col wide image. 
declare    SHOW_COLOR_DELAY=.25
declare    XWININFO="" ## Get the current window info via xwininfo.  
declare    X_COORD=""  ## Absolute upper-left X
declare    Y_COORD=""  ## Absolute upper-left Y
declare    REL_X=""    ## Relative upper-left X
declare    REL_Y=""    ## Relative upper-left Y

function show_colors() { 
 local -i ANSI=0
 tput clear 
  ## Print the mysterious ANSI colors. 
 for ANSI in {0..256} ; do 
  echo -en "\\033[38;5;${ANSI}m█\\033[0m" 
  (($((${ANSI}+1))%${COLOR_SWATCH_IMG_COLS}==0)) && echo 
 done 
 echo
} 

## Parse RGB hex tuples. 
## <Arg 1> - Hex: Input hex value [[:xdigit]]{6}
## <Arg 2> - String: Tuple [r|g|b]
function get_rgbtuple() { 
 local hexrgb="${1}" 
 local tuple_flag="${2}" 
 local tuple_fmt="${3:-x}" 
 local tuple="" 
 case "${tuple_flag}" in 
  r|R) 
   tuple=${hexrgb:0:2}
   ;; 
  g|G) 
   tuple=${hexrgb:2:2}
   ;; 
  b|B) 
   tuple=${hexrgb:4:2}
   ;; 
 esac
 echo $((0x${tuple}))
}

function get_rgb() { 
 local -i ansi=${1:-1}
 local -a rgb=("000000" "800000" "008000" "808000" "000080"     \
 "800080" "008080" "c0c0c0" "808080" "ff0000" "00ff00" "ffff00" \
 "0000ff" "ff00ff" "00ffff" "ffffff" "000000" "00005f" "000087" \
 "0000af" "0000d7" "0000ff" "005f00" "005f5f" "005f87" "005faf" \
 "005fd7" "005fff" "008700" "00875f" "008787" "0087af" "0087d7" \
 "0087ff" "00af00" "00af5f" "00af87" "00afaf" "00afd7" "00afff" \
 "00d700" "00d75f" "00d787" "00d7af" "00d7d7" "00d7ff" "00ff00" \
 "00ff5f" "00ff87" "00ffaf" "00ffd7" "00ffff" "5f0000" "5f005f" \
 "5f0087" "5f00af" "5f00d7" "5f00ff" "5f5f00" "5f5f5f" "5f5f87" \
 "5f5faf" "5f5fd7" "5f5fff" "5f8700" "5f875f" "5f8787" "5f87af" \
 "5f87d7" "5f87ff" "5faf00" "5faf5f" "5faf87" "5fafaf" "5fafd7" \
 "5fafff" "5fd700" "5fd75f" "5fd787" "5fd7af" "5fd7d7" "5fd7ff" \
 "5fff00" "5fff5f" "5fff87" "5fffaf" "5fffd7" "5fffff" "870000" \
 "87005f" "870087" "8700af" "8700d7" "8700ff" "875f00" "875f5f" \
 "875f87" "875faf" "875fd7" "875fff" "878700" "87875f" "878787" \
 "8787af" "8787d7" "8787ff" "87af00" "87af5f" "87af87" "87afaf" \
 "87afd7" "87afff" "87d700" "87d75f" "87d787" "87d7af" "87d7d7" \
 "87d7ff" "87ff00" "87ff5f" "87ff87" "87ffaf" "87ffd7" "87ffff" \
 "af0000" "af005f" "af0087" "af00af" "af00d7" "af00ff" "af5f00" \
 "af5f5f" "af5f87" "af5faf" "af5fd7" "af5fff" "af8700" "af875f" \
 "af8787" "af87af" "af87d7" "af87ff" "afaf00" "afaf5f" "afaf87" \
 "afafaf" "afafd7" "afafff" "afd700" "afd75f" "afd787" "afd7af" \
 "afd7d7" "afd7ff" "afff00" "afff5f" "afff87" "afffaf" "afffd7" \
 "afffff" "d70000" "d7005f" "d70087" "d700af" "d700d7" "d700ff" \
 "d75f00" "d75f5f" "d75f87" "d75faf" "d75fd7" "d75fff" "d78700" \
 "d7875f" "d78787" "d787af" "d787d7" "d787ff" "dfaf00" "dfaf5f" \
 "dfaf87" "dfafaf" "dfafdf" "dfafff" "dfdf00" "dfdf5f" "dfdf87" \
 "dfdfaf" "dfdfdf" "dfdfff" "dfff00" "dfff5f" "dfff87" "dfffaf" \
 "dfffdf" "dfffff" "ff0000" "ff005f" "ff0087" "ff00af" "ff00df" \
 "ff00ff" "ff5f00" "ff5f5f" "ff5f87" "ff5faf" "ff5fdf" "ff5fff" \
 "ff8700" "ff875f" "ff8787" "ff87af" "ff87df" "ff87ff" "ffaf00" \
 "ffaf5f" "ffaf87" "ffafaf" "ffafdf" "ffafff" "ffdf00" "ffdf5f" \
 "ffdf87" "ffdfaf" "ffdfdf" "ffdfff" "ffff00" "ffff5f" "ffff87" \
 "ffffaf" "ffffdf" "ffffff" "080808" "121212" "1c1c1c" "262626" \
 "303030" "3a3a3a" "444444" "4e4e4e" "585858" "626262" "6c6c6c" \
 "767676" "808080" "8a8a8a" "949494" "9e9e9e" "a8a8a8" "b2b2b2" \
 "bcbcbc" "c6c6c6" "d0d0d0" "dadada" "e4e4e4" "eeeeee")
 if ((ansi<=256)); then 
  printf "%s\n" "${rgb[${ansi}]}" 
  return 0 
 else 
  return 1
 fi
}

function print_coords(){ 
 local -i i=0 
 for((i=0;i<256;i++)){ 
  echo "IMG_TRU_XCOORD: ${IMG_TRU_XCOORD}, IMG_TRU_YCOORD: ${IMG_TRU_YCOORD}, IMG_XCOORD: ${IMG_XCOORD}, IMG_YCOORD: ${IMG_YCOORD}"
  get_next_x_coord
 }
}

function get_next_x_coord(){ 
 IMG_TRU_XCOORD=$(echo "scale=10;${IMG_TRU_XCOORD}+${CHAR_WIDTH}"|bc)
 if awk "BEGIN{exit !(${IMG_TRU_XCOORD}>(${COLOR_SWATCH_IMG_COLS}*${CHAR_WIDTH}))}"; then 
  IMG_TRU_XCOORD=$(echo "scale=10;${CHAR_WIDTH}*.5"|bc)
  get_next_y_coord
 fi
 IMG_XCOORD=$(awk -vtx=${IMG_TRU_XCOORD} 'BEGIN{printf("%1.f\n",tx)}')
}

function get_next_y_coord(){ 
 IMG_TRU_YCOORD=$(echo "scale=10;${IMG_TRU_YCOORD}+${CHAR_HEIGHT}"|bc)
 IMG_YCOORD=$(awk -vty=${IMG_TRU_YCOORD} 'BEGIN{printf("%1.f\n",ty)}')
}

function print_rgb(){ 
 local -i ANSI=0 
 local -i r=0 
 local -i g=0 
 local -i b=0 
 local    p_r="" 
 local    p_g="" 
 local    p_b="" 
 local    p_ANSI="" 
 local    ACTUAL_RGB=""
 local    xrgb_R=""
 local    xrgb_G=""
 local    xrgb_B=""
 local    xprgb_R=""
 local    xprgb_G=""
 local    xprgb_B=""
 local    xhex=""
 tput reset 
 for((ANSI=0;ANSI<256;ANSI++)){ 
  xhex=$(get_rgb "${ANSI}")
  xrgb_R=$(get_rgbtuple "${xhex}" "r")
  xrgb_G=$(get_rgbtuple "${xhex}" "g")
  xrgb_B=$(get_rgbtuple "${xhex}" "b")
  xprgb_R=$(printf "%3s" "${xrgb_R}")
  xprgb_G=$(printf "%3s" "${xrgb_G}")
  xprgb_B=$(printf "%3s" "${xrgb_B}")
  read -r -d=' ' r g b < <(convert "${SCREENSHOT_LOC}" -format  "%[fx:int(255*p{${IMG_XCOORD},${IMG_YCOORD}}.r)] %[fx:int(255*p{${IMG_XCOORD},${IMG_YCOORD}}.g)] %[fx:int(255*p{${IMG_XCOORD},${IMG_YCOORD}}.b)]" info:-)
  p_r=$(printf "%3s" "${r}")
  p_g=$(printf "%3s" "${g}")
  p_b=$(printf "%3s" "${b}")
  p_ANSI=$(printf "%3s" "${ANSI}")
  printf "\\033[38;5;${ANSI}m████ ANSI ${p_ANSI}\\033[0m|\\033[38;5;${ANSI}m%s%s\\033[0m|\x1b[38;2;${xrgb_R};${xrgb_G};${xrgb_B}mxterm-256color - RGB/TRUECOLOR - RGB:%s,%s,%s\\033[0m%s \\033[38;2;${r};${g};${b}mActual terminal RGB: %s ████\\033[0m\n" "HEX:0x" "${xhex}" "${xprgb_R}" "${xprgb_G}" "${xprgb_B}" " |" "srgb(${p_r},${p_g},${p_b})"
  get_next_x_coord
 }
}

function init() {
 ## Get xwindow info  
 XWININFO=$(xwininfo -id $(xdotool getactivewindow))
 ## Parse xwininfo data: 
 X_COORD=$(sed -nE 's/(^.*Absolute upper-left X:)( *)([0-9]+)/\3/p' <<< "${XWININFO}")
 Y_COORD=$(sed -nE 's/(^.*Absolute upper-left Y:)( *)([0-9]+)/\3/p' <<< "${XWININFO}") 
 REL_X=$(sed   -nE 's/(^.*Relative upper-left X:)( *)([0-9]+)/\3/p' <<< "${XWININFO}")
 REL_Y=$(sed   -nE 's/(^.*Relative upper-left Y:)( *)([0-9]+)/\3/p' <<< "${XWININFO}")  
 SCRN_WIDTH=$(sed -nE 's/(^.*Width:)( *)([0-9]+)/\3/p'   <<< "${XWININFO}")
 SCRN_HEIGHT=$(sed -nE 's/(^.*Height:)( *)([0-9]+)/\3/p'   <<< "${XWININFO}")
 ## Get terminal sizing
 SCRN_ROWS=$(tput lines)
 SCRN_COLS=$(tput cols)
 CHAR_WIDTH=$(echo "scale=10;${SCRN_WIDTH}/${SCRN_COLS}"|bc)
 CHAR_HEIGHT=$(echo "scale=10;${SCRN_HEIGHT}/${SCRN_ROWS}"|bc)
 ## IMG_TRU_XCOORD starts at half the terminal char width. Thereafter 
 ## we will move by a full character width rounded to the nearest 
 ## pixel. IMG_TRU_XCOORD will keep the accurate unrounded values and 
 ## the IMG_XCOORD is the rounded value needed for imageMagick.  
 IMG_TRU_XCOORD=$(echo "scale=10; ${CHAR_WIDTH}*.5"|bc)
 IMG_XCOORD=$(awk -vtx=${IMG_TRU_XCOORD} 'BEGIN{printf("%1.f\n",tx)}') 
 ## IMG_TRU_YCOORD starts at half the terminal char height. Thereafter 
 ## we will move down by a full char height after COLOR_SWATCH_IMG_COLS 
 ## columns have been calculated.  
 IMG_TRU_YCOORD=$(echo "scale=10; ${CHAR_HEIGHT}*.5"|bc)
 IMG_YCOORD=$(awk -vty=${IMG_TRU_YCOORD} 'BEGIN{printf("%1.f\n",ty)}')
 ## Screenshot coords 
 ## Add the relative offset to absolute coord to get the true coords. 
 let X_COORD+=${REL_X} ## Screenshot X Coord 
 let Y_COORD+=${REL_Y} ## Screenshot Y Coord
 ## Screenshot size  
 IMG_WIDTH=$(awk -viw=$(echo "scale=10;${COLOR_SWATCH_IMG_COLS}*${CHAR_WIDTH}"|bc) 'BEGIN{printf("%1.f\n",iw)}')
 IMG_HEIGHT=$(awk -vih=$(echo "scale=10;5*${CHAR_HEIGHT}"|bc) 'BEGIN{printf("%1.f\n",ih)}')
}

function main(){ 
 init 
 tput smcup ## Save screen. 
 rm -f "${SCREENSHOT_LOC}" 
 show_colors
 sleep ${SHOW_COLOR_DELAY}
 ## Take screenshot w/location and image dimensions. 
 scrot "${SCREENSHOT_LOC}" -a${X_COORD},${Y_COORD},${IMG_WIDTH},${IMG_HEIGHT}
 tput rmcup ## Restore screen.  
 print_rgb
 rm -f "${SCREENSHOT_LOC}" 
}

main 
exit 0
Get the latest on GitHub.