How to get the RGB values of a 256-color palette terminal color - terminal

Thanks to ANSI escape codes, when you run:
echo -e "\e[38;5;74mHi"
This will display "Hi", colored with the palette color 74 (commonly a blue/cyan, but it may be another color, depending on the defined palette):
But how can I retrieve the red/green/blue components of the given color (74 in this example) actually shown by the terminal emulator?
Expected result
Run this imaginary command in bash:
$ palette-to-rgb 74
Expected output:
#5fafd7 # Or any other parsable output like rgb(95,175,215)
What did I try
The only (ugly) way I found to get the RGB components is to make a screenshot and use some graphical program like gimp to retrieve the RGB values.

I think it's not possible to retrieve the color codes programmatically. A possible way would be a kind of ANSI sequence,
but it doesn't seem to exist.
So as a workaround, it is possible to get the standard values; I made this bash script for this aim (for int calculations, I got help from the source of st):
#!/bin/bash
usage() {
echo "palette-to-rgb [COL] [-rgb] [-raw] [-C] [-h]"
echo "Show RGB values of the standard terminal 256-color palette."
echo "If COL is given (number 0-255), show only the given color."
echo "Options:"
echo " -rgb Format as \"rgb(R, G, B)\" instead of \"#RRGGBB\""
echo " -raw Show the value only"
echo " -C Force coloring even when piped"
}
std_colors=(
0 0 0 # 0 black
128 0 0 # 1 red
0 128 0 # 2 green
128 128 0 # 3 yellow
0 0 128 # 4 blue
128 0 128 # 5 magenta
0 128 128 # 6 cyan
192 192 192 # 7 white (light grey)
128 128 128 # 8 grey
255 0 0 # 9 bright red
255 255 0 # 10 bright green
0 255 0 # 11 bright yellow
0 0 255 # 12 bright blue
255 0 255 # 13 bright magenta
0 255 255 # 14 bright cyan
255 255 255 # 15 bright white
)
# 6x6x6 cube color component
cube_component() {
local i=$(( (($1 - 16) / $2) % 6 ))
(( $i == 0 )) && echo 0 || echo $(( ( 14135 + 10280 * $i ) / 256 ))
}
get_color() {
local r g b fmt
if (( $1 < 16 )); then
r=${std_colors[$(( $1 * 3 + 0 ))]}
g=${std_colors[$(( $1 * 3 + 1 ))]}
b=${std_colors[$(( $1 * 3 + 2 ))]}
elif (( $1 < 232 )); then # < 6*6*6+16 ?
# colors 16-231 (6x6x6 cube):
r=$(cube_component $1 36)
g=$(cube_component $1 6)
b=$(cube_component $1 1)
else
# colors 232-255 (grayscale):
r=$(( ( 2056 + 2570 * ($1 - 232) ) / 256 ))
g=$r
b=$r
fi
[[ -n $rgb ]] && fmt='rgb(%i, %i, %i)' || fmt='#%02x%02x%02x'
printf "$fmt\n" $r $g $b
}
print_color() {
if [[ -n $raw ]]; then
get_color $1
else
# Show a colored box if not piped (or with option -C)
[[ -t 1 || -n $colored ]] && echo -en "\e[48;5;${1}m \e[0m "
printf '%03i: %s\n' $1 "$(get_color $1)"
fi
}
color= colored= rgb= raw=
for arg in "$#"; do
if [[ $arg == -h ]]; then usage; exit
elif [[ $arg =~ ^[0-9]+$ ]]; then
(( $arg > 255 )) && { echo "Wrong color code" >&2; exit 1; }
color=$arg
elif [[ $arg == -C ]]; then colored=1
elif [[ $arg == -rgb ]]; then rgb=1
elif [[ $arg == -raw ]]; then raw=1
else echo "Wrong arg: $arg" >&2; exit 1
fi
done
if [[ -n $color ]]; then
print_color $color
else
for n in {0..255}; do
print_color $n
done
fi
Output:
000: #000000
001: #800000
002: #008000
003: #808000
004: #000080
005: #800080
006: #008080
007: #c0c0c0
008: #808080
009: #ff0000
010: #ffff00
011: #00ff00
012: #0000ff
013: #ff00ff
014: #00ffff
015: #ffffff
016: #000000
017: #00005f
018: #000087
019: #0000af
020: #0000d7
021: #0000ff
022: #005f00
023: #005f5f
024: #005f87
025: #005faf
026: #005fd7
027: #005fff
028: #008700
029: #00875f
030: #008787
031: #0087af
032: #0087d7
033: #0087ff
034: #00af00
035: #00af5f
036: #00af87
037: #00afaf
038: #00afd7
039: #00afff
040: #00d700
041: #00d75f
042: #00d787
043: #00d7af
044: #00d7d7
045: #00d7ff
046: #00ff00
047: #00ff5f
048: #00ff87
049: #00ffaf
050: #00ffd7
051: #00ffff
052: #5f0000
053: #5f005f
054: #5f0087
055: #5f00af
056: #5f00d7
057: #5f00ff
058: #5f5f00
059: #5f5f5f
060: #5f5f87
061: #5f5faf
062: #5f5fd7
063: #5f5fff
064: #5f8700
065: #5f875f
066: #5f8787
067: #5f87af
068: #5f87d7
069: #5f87ff
070: #5faf00
071: #5faf5f
072: #5faf87
073: #5fafaf
074: #5fafd7
075: #5fafff
076: #5fd700
077: #5fd75f
078: #5fd787
079: #5fd7af
080: #5fd7d7
081: #5fd7ff
082: #5fff00
083: #5fff5f
084: #5fff87
085: #5fffaf
086: #5fffd7
087: #5fffff
088: #870000
089: #87005f
090: #870087
091: #8700af
092: #8700d7
093: #8700ff
094: #875f00
095: #875f5f
096: #875f87
097: #875faf
098: #875fd7
099: #875fff
100: #878700
101: #87875f
102: #878787
103: #8787af
104: #8787d7
105: #8787ff
106: #87af00
107: #87af5f
108: #87af87
109: #87afaf
110: #87afd7
111: #87afff
112: #87d700
113: #87d75f
114: #87d787
115: #87d7af
116: #87d7d7
117: #87d7ff
118: #87ff00
119: #87ff5f
120: #87ff87
121: #87ffaf
122: #87ffd7
123: #87ffff
124: #af0000
125: #af005f
126: #af0087
127: #af00af
128: #af00d7
129: #af00ff
130: #af5f00
131: #af5f5f
132: #af5f87
133: #af5faf
134: #af5fd7
135: #af5fff
136: #af8700
137: #af875f
138: #af8787
139: #af87af
140: #af87d7
141: #af87ff
142: #afaf00
143: #afaf5f
144: #afaf87
145: #afafaf
146: #afafd7
147: #afafff
148: #afd700
149: #afd75f
150: #afd787
151: #afd7af
152: #afd7d7
153: #afd7ff
154: #afff00
155: #afff5f
156: #afff87
157: #afffaf
158: #afffd7
159: #afffff
160: #d70000
161: #d7005f
162: #d70087
163: #d700af
164: #d700d7
165: #d700ff
166: #d75f00
167: #d75f5f
168: #d75f87
169: #d75faf
170: #d75fd7
171: #d75fff
172: #d78700
173: #d7875f
174: #d78787
175: #d787af
176: #d787d7
177: #d787ff
178: #d7af00
179: #d7af5f
180: #d7af87
181: #d7afaf
182: #d7afd7
183: #d7afff
184: #d7d700
185: #d7d75f
186: #d7d787
187: #d7d7af
188: #d7d7d7
189: #d7d7ff
190: #d7ff00
191: #d7ff5f
192: #d7ff87
193: #d7ffaf
194: #d7ffd7
195: #d7ffff
196: #ff0000
197: #ff005f
198: #ff0087
199: #ff00af
200: #ff00d7
201: #ff00ff
202: #ff5f00
203: #ff5f5f
204: #ff5f87
205: #ff5faf
206: #ff5fd7
207: #ff5fff
208: #ff8700
209: #ff875f
210: #ff8787
211: #ff87af
212: #ff87d7
213: #ff87ff
214: #ffaf00
215: #ffaf5f
216: #ffaf87
217: #ffafaf
218: #ffafd7
219: #ffafff
220: #ffd700
221: #ffd75f
222: #ffd787
223: #ffd7af
224: #ffd7d7
225: #ffd7ff
226: #ffff00
227: #ffff5f
228: #ffff87
229: #ffffaf
230: #ffffd7
231: #ffffff
232: #080808
233: #121212
234: #1c1c1c
235: #262626
236: #303030
237: #3a3a3a
238: #444444
239: #4e4e4e
240: #585858
241: #626262
242: #6c6c6c
243: #767676
244: #808080
245: #8a8a8a
246: #949494
247: #9e9e9e
248: #a8a8a8
249: #b2b2b2
250: #bcbcbc
251: #c6c6c6
252: #d0d0d0
253: #dadada
254: #e4e4e4
255: #eeeeee
A related question: How to generate 256 color palette for Linux terminal in HTML/jquery

Try this for hex codes:
xdef="$HOME/.Xresources"
colors=( $( sed -re '/^!/d; /^$/d; /^#/d; s/(\*color)([0-9]):/\10\2:/g;' $xdef | grep 'color[01][0-9]:' | sort | sed 's/^.*: *//g' )
)
echo
for i in {0..7}; do echo -en "\e[$((30+$i))m ${colors[i]} \u2588\u2588 \e[0m"; done
echo
for i in {8..15}; do echo -en "\e[1;$((22+$i))m ${colors[i]} \u2588\u2588 \e[0m"; done
echo -e "\n"
All credits to https://github.com/stark/color-scripts/blob/master/color-scripts/hex-block .
Note that this script won't work on macOS.
And this for color with escape codes:
T='•••' # The text for the color test
echo -e "\n def 40m 41m 42m 43m 44m 45m 46m 47m";
for FGs in ' m' ' 1m' ' 30m' '1;30m' ' 31m' '1;31m' ' 32m' \
'1;32m' ' 33m' '1;33m' ' 34m' '1;34m' ' 35m' '1;35m' \
' 36m' '1;36m' ' 37m' '1;37m';
do FG=${FGs// /}
echo -en " $FGs \033[$FG $T "
for BG in 40m 41m 42m 43m 44m 45m 46m 47m;
do echo -en "$EINS \033[$FG\033[$BG $T \033[0m";
done
echo;
done
echo
Source: https://github.com/stark/color-scripts/blob/master/color-scripts/colortest .

Related

Linux shell script for brightness of all monitors

I have found a script to set the brightness of all monitors at once which works using it with one option but not with another option.
The script is (Below Best Answer):
https://itectec.com/ubuntu/ubuntu-control-monitor-brightness-with-keyboard-shortcut/
b=$(xrandr --current --verbose | grep Brightness)
b=${b#*: } # Remove "Brightness: "
b=${b#0.} # 0.30 --> 30
[[ $b == "1.0" ]] && b="100"
case $1 in
+*|-*)
b=$((b $1)) # LINE 19 b=b+10, b=b-10
;;
[0-9]*) # LINE 21
b=$1 # b=75
;;
*) # LINE 24
echo $b; exit
;;
esac
So it works if I do:
brightness 90
But not if I try to increase or decrease the current brightness:
brightness +10
/usr/local/bin/brightness: line 19: 90
Brightness: 0.90: syntax error in expression (error token is "Brightness: 0.90")
/usr/local/bin/brightness: line 21: [[: 90
Brightness: 0.90: syntax error in expression (error token is "Brightness: 0.90")
/usr/local/bin/brightness: line 22: [[: 90
Brightness: 0.90: syntax error in expression (error token is "Brightness: 0.90")
/usr/local/bin/brightness: line 24: [[: 90
Brightness: 0.90: syntax error in expression (error token is "Brightness: 0.90")
xrandr: unrecognized option 'Brightness:'
Try 'xrandr --help' for more information.
xrandr: unrecognized option 'Brightness:'
Try 'xrandr --help' for more information.
Any idea?

Wrong read from a named pipe

I have a script which reads commands from a named pipe:
#! /usr/bin/env bash
host_pipe="host-pipe"
#pipe for executing commands
[ -p "$host_pipe" ] || mkfifo -m 0600 "$host_pipe" || exit 1
chmod o+w "$host_pipe"
set -o pipefail
while :; do
if read -r cmd <$host_pipe; then
if [ "$cmd" ]; then
printf 'Running: %s \n' "$cmd"
fi
fi
done
I run it and test with command:
bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"
bash -c "echo 'abcdef' > host-pipe"
And get the strange output:
Running: abcdf
Running: abcdef
Running: abcde
Running: abcdf
Running: ace
Somehow the script can't read all the string it get from the pipe? How to read it?
You must have more than one reader of the named pipe host-pipe running for this to happen.
Check to see if you have a second instance of the script running in the background or possibly in another terminal.
Explanation
You will find that bash will issue reads from the pipe 1 byte at a time. If you are on Linux, you can strace your script. Here is an excerpt:
open("host-pipe", O_RDONLY|O_LARGEFILE) = 3
fcntl64(0, F_GETFD) = 0
fcntl64(0, F_DUPFD, 10) = 10
fcntl64(0, F_GETFD) = 0
fcntl64(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 0) = 0
close(3) = 0
ioctl(0, TCGETS, 0xbf99bfec) = -1 ENOTTY (Inappropriate ioctl for device)
_llseek(0, 0, 0xbf99c068, SEEK_CUR) = -1 ESPIPE (Illegal seek)
read(0, "a", 1) = 1
read(0, "b", 1) = 1
read(0, "c", 1) = 1
read(0, "d", 1) = 1
read(0, "e", 1) = 1
read(0, "f", 1) = 1
read(0, "\n", 1) = 1
dup2(10, 0) = 0
fcntl64(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
Once you have more than one process with this consumption pattern, any single process will see lost characters.

EOL error (unexpected EOF while looking for matching `)')

If I start the script from this error:
./Sinusbot.sh: line 276: unexpected EOF while looking for matching `)'
./Sinusbot.sh: line 305: syntax error: unexpected end of file
Part of the affected script:
echo -e "$info Configuring instances"
if [ "$ydl" = "y" ] || [ "$ydl" = "Y" ]; then
c2="0"
while [ $c2 = $nbot ]
do
c2=$((c2+1) #Line 276
bport=$((bport+1)
cd
cd Sinus-$2
cat > config.ini << EOL
ListenPort = ${bport}
ListenHost = "0.0.0.0"
TS3Path = "TeamSpeak3-Client-linux_amd64/ts3client_linux_amd64"
YoutubeDLPath = "youtube-dl"
DataDir = "data/"
EOL
done
else
while [ $c2 = $nbot ]
do
c2=$((c2+1)
bport=$((bport+1)
cd
cd Sinus-$2
cat > config.ini << EOL
ListenPort = ${bport}
ListenHost = "0.0.0.0"
TS3Path = "TeamSpeak3-Client-linux_amd64/ts3client_linux_amd64"
DataDir = "data/"
EOL
done
fi
#line 305
Why does this happen and how can I fix it?
In addition to notepad ++ all the lines appear blue since I put "cat" config.ini << EOL "how come? And how can I take it off?
image notepad ++
These lines have 2 starting parenthesis but only one finishing parenthesis:
c2=$((c2+1)
bport=$((bport+1)
Considering the indentation of your program, you probably want to close them by adding a closing parenthesis top each line:
c2=$((c2+1))
bport=$((bport+1))
Arithmetic Expansion - $(())
close missed parenthesis

how to properly read from stream in bash

I am reading from the shared memory a stream producing an infinite information output such as:
0x1 (TimeStamp) 12Bytes:11216 + 1771/(47999+1) (0.036896) delta= 0+ 1536/(47999+1) (0.032000) 11216.013361 23.534ms 2015.06.25 11:51:16.525
0x4 (ReferenceTime) 12Bytes:11215 + 24786286/(26999999+1) (0.918011) delta= 0+ 806359/(26999999+1) (0.029856) 11216.013376 -95.366ms 2015.06.25 11:51:16.525
0x6 (ProcessDelay) 4Bytes: 32 (0x20)
0x7 (ClockAccuracy) 8Bytes: offset=0.000ppm (+-0.000ppm)
0xb (ClockId) 8Bytes: 01 00 00 00 42 22 01 00
0x20001 (SampleRate) 4Bytes: 48000 (0xbb80)
0x20002 (Channels) 4Bytes: 6 (0x6)
0x20003 (PcmLevel) 24Bytes: -11041 -11541 -49076 -86121 -24846 -24382
0x20004 (PcmPeak) 24Bytes: -8088 -8697 -37244 -84288 -21437 -21769
0x2000e (DolbyDpMetadata) 39352Bytes:
Linear Time: 11216 + 1771/(47999+1) (0.036896) delta= 0+ 1536/(47999+1) (0.032000)
if i try to read the stream with the following command:
while read line;
do
echo "$line";
echo "im here!"
done < <(../tools/spucat adec-68)
wherespucat is a cpp binary exacutable that continuosly print out on console using printf() information about incoming data packets.
this is the result:
im here!
�k�G��E�x����b��h�������c����2��/n��-�U���QE�L�x���c�������������������������������x��4����O��M�����/��(������������������~��E�*�������;
im here!
������r��$�|��J�n�P�4�
if i start the script whit this command:
while read line;
do
echo "$line";
echo "im here!"
done < $(../tools/spucat adec-68)
it actually never go inside the while loop, just start to print out the stream whaiting for the end.
Is tehere a way to read it line by line and process it inside the while loop?
spucat is dumping to the standard error (no idea why), so to processing it must be redirect to the standard output:
while read -r line;
do
echo "$line";
echo "im here!"
done < <(../tools/spucat -p 4 adec-68 2>&1 > /dev/null)

How to draw a graph from text file in bash?

I have a text file, each line of which contains two blank separated fields: x and y.
1 0
10 29
5 2
Now I would like to see the graph of y = f(x), where x and y are taken from the file.
I would prefer a curses picture in a terminal but it can be a picture in any graphics format as well.
What is the easiest way to do it in bash?
Here's a very funny possibility. The thing I'm going to show you here is probably not what you're looking for, it's probably not optimized, it's probably a whole bunch of junk, but it's really funny. (I'm not expecting any upvotes for it).
This script more or less plots a * at each point the coordinates of which are given in a file (given as first argument of the script). It computes the number of rows and columns of your terminal (using the command stty, if you happen to have it installed, it's good, otherwise, well, it's not going to work).
#!/bin/bash
isnumber() {
for i; do
[[ "$i" =~ [[:digit:]] ]] || return 1
[[ "$i" =~ ^[+-]?[[:digit:]]*\.?[[:digit:]]*$ ]] || return 1
done
return 0
}
die() {
echo >&2 "$#"
exit 1
}
[[ -n $1 ]] || die "You must provide an argument"
xarray=()
yarray=()
# Read file input
while read x y _; do
isnumber "$x" "$y" || continue
xarray+=( "$x" )
yarray+=( "$y" )
done < "$1"
# Check that we have at least one point
(( ${#xarray[#]} )) || die "Error, there's no valid point inf file \`$1'"
# Compute xmin, xmax, ymin and ymax:
read xmin xmax ymin ymax valid < <(
bc -l < <(
echo "ymin=${yarray[0]}; ymax=${yarray[0]}"
echo "xmin=${xarray[0]}; xmax=${xarray[0]}"
for i in "${!xarray[#]}"; do
echo "y=${yarray[i]}; if (ymax<y) ymax=y; if (ymin>y) ymin=y"
echo "x=${xarray[i]}; if (xmax<x) xmax=x; if (xmin>x) xmin=x"
done
echo 'print xmin," ",xmax," ",ymin," ",ymax'
# This will tell us if we have xmin<xmax and ymin<ymax
echo 'print " ",(xmin<xmax)*(ymin<ymax)'
)
)
# Check that xmin<xmax and ymin<ymax
(( valid )) || die "Error, ! ( (xmin<xmax) && (ymin<ymax) )"
# Get terminal's number of rows and columns
IFS=' ;' read _ _ _ _ nbrows _ nbcols _ < <(stty -a)
((nbrows-=1))
((maxcols=nbcols-1))
((maxrows=nbrows-1))
# Create an array full of spaces:
points=()
for ((i=0;i<nbrows*nbcols;++i)); do points+=( ' ' ); done
# Put a '*' at each x y in array points
while read r c; do
printf -v X "%.f" "$c"
printf -v Y "%.f" "$r"
points[X+Y*nbcols]='*'
done < <(
bc -l < <(
echo "xmin=$xmin; dx=$maxcols/($xmax-xmin)"
echo "ymax=$ymax; dy=$maxrows/(ymax-($ymin))"
for i in "${!xarray[#]}"; do
echo "print (ymax-(${yarray[i]}))*dy,\" \",(${xarray[i]}-xmin)*dx,\"\n\""
done
)
)
# Now, print it! The clear is not mandatory
clear
printf "%c" "${points[#]}"
Call the script plot_file_in_terminal (or maybe a shorter name).
You can try it, it's very funny, with a Mandelbrot set: the following script generates an M-set (you can give the number of pixels for the x and y coordinates as input, well, figure out a few things by yourself):
#!/bin/bash
die() {
echo >&2 "$#"
exit 1
}
nbx=${1:-100}
nby=${2:-100}
Nmax=${3:-100}
[[ $nbx =~ ^[[:digit:]]+$ ]] && ((nbx>5)) || die "First argument (nbx) must be an integer > 5"
[[ $nby =~ ^[[:digit:]]+$ ]] && ((nby>5)) || die "Second argument (nby) must be an integer > 5"
[[ $Nmax =~ ^[[:digit:]]+$ ]] && ((Nmax>5)) || die "Third argument (Nmax) must be an integer > 5"
xmin=-1.5
xmax=1
ymin=-1
ymax=1
bc -l <<EOF
for (k=0;k<$nbx;++k) {
for (l=0;l<$nby;++l) {
x0=k*($xmax-($xmin))/($nbx-1)+($xmin)
y0=l*($ymax-($ymin))/($nby-1)+($ymin)
x=x0
y=y0
isin=1
for (i=0;i<$Nmax;++i) {
if(x^2+y^2>1) {
isin=0
break
}
xn=x^2-y^2+x0
y=2*x*y+y0
x=xn
}
if(isin) print x0," ",y0,"\n"
}
}
EOF
Name it genMandelbrot and use it as ./genMandelbrot > Mset or ./genMandelbrot 100 50 > Mset if your terminal is more or less 100x50. Then:
./plot_file_in_terminal Mset
Nice, eh?
If you want a sine function (say from 0 to 2*pi):
bc -l <<< "for (i=0;i<400;++i) { x=i*6.28/400; print x,\" \",s(x),\"\\n\" }" > sine
Then call:
./plot_file_in_terminal sine
Outputs
Mandelbrot Set (in 80x24)
**
**********
***********
* *************** * *
*********************************** ****
**************************************** *
**********************************************
**************************************************
************** **************************************************
******************** ****************************************************
** **************************************************************************
****************************************************************************
** **************************************************************************
******************** ****************************************************
************** **************************************************
**************************************************
**********************************************
**************************************** *
*********************************** ****
* *************** * *
***********
**********
**
gniourf#somewhere:~/cool_path$
Sine (in 80x24)
*********
**** ***
*** **
** **
** **
** **
*** **
** **
** **
** **
** **
* ** *
** **
** **
** **
** **
** **
*** **
** **
*** ***
*** ***
*** ****
********
gniourf#somewhere:~/an_even_cooler_path$
In your OP you mentionned "the easiest way of doing"... well, you can notice, this solution it's not exactly a one-liner.
Edits.
Robustness: check that xmin!=xmax and ymin!=ymax so as to not divide by 0
Speed: Computing xmin, xmax, ymin, ymax in the same bc instance.
Speed: Don't use tput anymore, it was retarded and too slow! Instead, build an array of points (each field contains a space or *).
Todos.
Lots of stuff to have something we can actually work with confortably. This exercise is left to the reader.

Resources