You are not logged in.
Thanks for reading this post.
I'm trying to learn shell scripts. I learned yesterday that with
script test
the shell commands are recorded and written to a file
test
, with CTRL + D the recording is stopped, pretty neat.
For example
#!/bin/sh
cat << "EOF"
${c2} .KMM
${c3};MM
${c4}.MM
EOF
concacenate until EndOfFile, basically print everything between "EOF" and EOF, I believe I understand.
#!/bin/sh
echo "${c2} .KMM
${c3};MM
${c4}.MM"
${c2,3,4} aren't printed because $ , { and } are escape characters, correct?
Then this is also understandable.
Where it get's confusing is when I took this snippet from the neofetch script and would like to know how to print colored with the ${c1,2,3..}
I understand the snippet is really complicated and I'm not trying to understand it.
My interest is focused on the syntax of printf, set_colors and escape characters in that example.
The focus on the specific things is most likely the reason why I don't understand it because I'm missing the basics.
#!/usr/bin/env bash
printf '%b\n' "$ascii_data${reset}"
LC_ALL=C
set_colors 2 3 1 1 5 4
read -rd '' ascii_data <<'EOF'
${c2} .KMM
${c3};MM
${c4}.MM
;;
I hope that it's understandable, that I'm curious about this specific topic.
Last edited by Gill Bates (2022-11-20 18:35:31)
Offline
There is no escape sequences in this script.
Your script script contains something that would be parameter expansions of variables named `c2`, `c3` and `c4`. But it is not, because the code uses a quoted heredoc, which prevents expansion.
The last script uses printf (bash builtin) to print contents of its argument. That argument is composed of expansion of variables `ascii_data` and `reset`. Since the %b format is used, escape sequences contained in that expanded string are interpreted by `printf`. Both variables are set before the script starts. Then it uses `set_colors`, which I have no idea where it comes from, so I will not comment on that part. Finally… finally there is a part that makes no sense and is syntactically invalid. Is this the actual script or did you remove fragments of it? There is a call to read (bash builtin) to read data from a heredoc into a variable, but that part is a mess that can’t even be executed.
Sometimes I seem a bit harsh — don’t get offended too easily!
Offline
Thank you for your reply and shine some light into the dark.
Thanks to your answer, my question is actually: How to used printf with parameter expansions?
Now I can use a searchengine with that term "parameter expansion".
I'm trying to prove that I'm really trying to figure this out myself, but the lack of vocabulary makes it hard.
The goal is the most primitiv, simple shell script with printf, parameter expansion (to define colors) and print a small ASCII-art, thinking that would be a good learning experience.
The entire script is here:
https://github.com/dylanaraps/neofetch/ … r/neofetch
I thought this would show, but it's so embarassing I messed up copy paste.
print_ascii() {
if [[ -f "$image_source" && ! "$image_source" =~ (png|jpg|jpeg|jpe|svg|gif) ]]; then
ascii_data="$(< "$image_source")"
elif [[ "$image_source" == "ascii" || $image_source == auto ]]; then
:
else
ascii_data="$image_source"
fi
# Set locale to get correct padding.
LC_ALL="$sys_locale"
# Calculate size of ascii file in line length / line count.
while IFS=$'\n' read -r line; do
line=${line//\\\\/\\}
line=${line//█/ }
((++lines,${#line}>ascii_len)) && ascii_len="${#line}"
done <<< "${ascii_data//\$\{??\}}"
# Fallback if file not found.
((lines==1)) && { lines=; ascii_len=; image_source=auto; get_distro_ascii; print_ascii; return; }
# Colors.
ascii_data="${ascii_data//\$\{c1\}/$c1}"
ascii_data="${ascii_data//\$\{c2\}/$c2}"
ascii_data="${ascii_data//\$\{c3\}/$c3}"
ascii_data="${ascii_data//\$\{c4\}/$c4}"
ascii_data="${ascii_data//\$\{c5\}/$c5}"
ascii_data="${ascii_data//\$\{c6\}/$c6}"
((text_padding=ascii_len+gap))
printf '%b\n' "$ascii_data${reset}"
LC_ALL=C
}
get_distro_ascii() {
# This function gets the distro ascii art and colors.
#
# $ascii_distro is the same as $distro.
case $(trim "$ascii_distro") in
"arch_small")
set_colors 6 7 1
read -rd '' ascii_data <<'EOF'
${c1} /\\
/ \\
/\\ \\
${c2} / \\
/ ,, \\
/ | | -\\
/_-'' ''-_\\
EOF
;;
esac
;;
esac
# Overwrite distro colors if '$ascii_colors' doesn't
# equal 'distro'.
[[ ${ascii_colors[0]} != distro ]] && {
color_text=off
set_colors "${ascii_colors[@]}"
}
}
Last edited by Gill Bates (2022-11-16 13:01:10)
Offline
`printf` doesn’t perform parameter expansion. Shell (bash in this case) does. `printf` only prints its arguments.⁽¹⁾
The `read` part is an idiom to assign text to a variable. The text is assigned as-in, exactly as typed. Compare:
#!/usr/bin/env bash
read -rd '' music <<'EOF'
$not_expanded \ ,---. /
- (]-.-[) -
/ \
EOF
echo "$music"
The `set_colors` command in neofetch’s source is their own definition. It sets a bunch of variables, named `c1`, `c2`, `c3`, …, `c6` to escape sequences setting colors in the terminal. What may be confusing is that, what looks like a variable expansion in the ASCII art heredoc, is in fact not expansion. It’s just arbitrary string. That string is later manually replaced (not expanded by shell!) using the ${parameter//pat/string} expansion. Compare:
#!/usr/bin/env bash
read -rd '' music <<'EOF'
$not_expanded \ ,---. /
- (]-.-[) -
/ \
EOF
echo "${music//\$not_expanded/ REPLACED }"
something=' Ping! Ping! '
echo "${music//\$not_expanded/$something}"
echo "${music//-.-/O.O}"
Pay attention to `$not_expanded` never being used as a variable. It’s just a manually replaced piece of text. Neofetch authors must’ve used the format to be clear, what this will be replaced with later.
____
⁽¹⁾ With that single exception of the %b format, which acts as `echo -e`. But that only affects escape sequences. It will not perform any parameter substitution.
Last edited by mpan (2022-11-16 14:40:27)
Sometimes I seem a bit harsh — don’t get offended too easily!
Offline
I want to thank you for your in-depth reply.
I followed your instructions and compared, at first I thought where is this leading, but you literally explained me so much in such an efficient way, leading me to this:
#!/usr/bin/env bash
read -rd '' music <<'EOF'
${c1} 'c.
,xNMM.
.OMMMMo
OMMM0,
.;loddo:' loolloddol;.
cKMMMMMMMMMMNWMMMMMMMMMM0:
${c2} .KMMMMMMMMMMMMMMMMMMMMMMMWd.
XMMMMMMMMMMMMMMMMMMMMMMMX.
${c3};MMMMMMMMMMMMMMMMMMMMMMMM:
:MMMMMMMMMMMMMMMMMMMMMMMM:
${c4}.MMMMMMMMMMMMMMMMMMMMMMMMX.
kMMMMMMMMMMMMMMMMMMMMMMMMWd.
${c5}.XMMMMMMMMMMMMMMMMMMMMMMMMMMk
.XMMMMMMMMMMMMMMMMMMMMMMMMK.
${c6}kMMMMMMMMMMMMMMMMMMMMMMd
;KMMMMMMMWXXWMMMMMMMk.
.cooc,. .,coo:.
EOF
echo "$music"
Which outputs what I wanted and you taught me about 'read'.
I believe I understood through testing what you wanted me to understand with
echo "${music//\$not_expanded/ REPLACED }"
something=' Ping! Ping! '
echo "${music//\$not_expanded/$something}"
I tested this in the terminal and specially this:
echo "${music//-.-/O.O}"
made me think, a logo could also be printed like this
#!/usr/bin/env bash
R='\033[0;31m' #'0;31' is Red's ANSI color code
G='\033[0;32m' #'0;32' is Green's ANSI color code
Y='\033[1;32m' #'1;32' is Yellow's ANSI color code
B='\033[0;34m' #'0;34' is Blue's ANSI color code
echo -e "${R}firstline\n${Y}secondline\n${G}thirdline\n"
Now I'm only wondering which lines of the script are coloring the logo ?
With echo -e I can fiddle a solution together, but I would love to understand how the author of neofetch did it.
Last edited by Gill Bates (2022-11-16 16:13:54)
Offline
neofetch blindly assumes the terminal supports ANSI SGR control codes:
#!/usr/bin/env bash
for ((i=0; i<16; ++i)); do
echo -e "\e[38;5;${i}m COLORS!"
done
echo -e '\e[0m'
A portable way of doing this is by using tput with the `setaf` property:
#!/usr/bin/env bash
for ((i=0; i<16; ++i)); do
tput setaf "$i"
echo COLORS!
done
tput sgr0
Sometimes I seem a bit harsh — don’t get offended too easily!
Offline
neofetch blindly assumes the terminal supports ANSI SGR control codes:
#!/usr/bin/env bash for ((i=0; i<16; ++i)); do echo -e "\e[38;5;${i}m COLORS!" done echo -e '\e[0m'
A portable way of doing this is by using tput with the `setaf` property:
#!/usr/bin/env bash for ((i=0; i<16; ++i)); do tput setaf "$i" echo COLORS! done tput sgr0
Thank you for your replies.
I'm sure you're trying to teach me a even better way to code, given that you write " [...] blindly assumes the terminal supports ANSI SGR control codes ".
I have to do some catching up read about ANSI, ASCII understand all those terms.
Meanwhile, I still don't understand how {c2} {c3} ... are coloring the lines behind it, is https://github.com/dylanaraps/neofetch/ … etch#L4086
this the part where c2, c3 ... are defined ?
Am I looking at the right place at least?
https://github.com/dylanaraps/neofetch/ … etch#L5987
Thanks for your time, have a great weekend.
Last edited by Gill Bates (2022-11-18 17:16:11)
Offline
FWIW, this is an odd script to study if you want to learn about shell scripting. This script does many things in very atypical / unusual ways, and arguably does many things that are not very good practice.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Unarguably I agree with Trilby regarding learning scripting. Just that part alone is confusing, despite it’s a sane choice prevalent in many programs.⁽¹⁾
Ignore the colors for now, as I feel we have trouble at much more basic level. Please study again and understand replacement example I provided. I will repeat: names in that heredoc are arbitrary strings. For convenience named like the corresponding variables. But those are not variables, not variable expansions, and shell has no idea about them at any point of execution. Those could be named “dog”, “$$c$$$a$$${{}{}{}$t” or “‰¿£‰¢½³” with no change in behavior.⁽²⁾
Variables (not strings in the heredoc!) `c1` through `c6` are set by invocation of `set_colors`. As I already said. I also don’t get the question about being on the right track: you are linking to a fragment of source, which I already directed you to.
Until some
____
⁽¹⁾ Using placeholder tokens named after variables from which actual values are taken. To be clear about what I am referring to.
⁽²⁾ Assuming the replacement pattern is updated accordingly, of course.
Last edited by mpan (2022-11-18 17:48:10)
Sometimes I seem a bit harsh — don’t get offended too easily!
Offline
Variables (not strings in the heredoc!) `c1` through `c6` are set by invocation of `set_colors`. As I already said. I also don’t get the question about being on the right track: you are linking to a fragment of source, which I already directed you to.
Please just execute the script and change nothing but interchange the {c2,3,4} with eachother and magicially the colors are changing, so no offense but this is definitely responsible for changing the colors.
Anyway folks, I think it's very hard for you to understand how noob I am.
All I want is this:
#!/usr/bin/zsh
printf "\x1b[92m\x1b[104m 'c. \x1b[0m\n";
printf "\x1b[92m\x1b[104m ,xNMM. \x1b[0m\n";
printf "\x1b[92m\x1b[104m .OMMMMo \x1b[0m\n";
printf "\x1b[92m\x1b[104m OMMM0, \x1b[0m\n";
printf "\x1b[92m\x1b[104m .;loddo:' loolloddol;. \x1b[0m\n";
printf "\x1b[92m\x1b[104m cKMMMMMMMMMMNWMMMMMMMMMM0: \x1b[0m\n";
printf "\x1b[93m\x1b[105m .KMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m\n";
printf "\x1b[93m\x1b[105m XMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m\n";
printf "\x1b[33m\x1b[101m ;MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m\n";
printf "\x1b[33m\x1b[101m :MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m\n";
printf "\x1b[91m\x1b[103m .MMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m\n";
printf "\x1b[91m\x1b[103m kMMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m\n";
printf "\x1b[35m\x1b[103m .XMMMMMMMMMMMMMMMMMMMMMMMMMMk \x1b[0m\n";
printf "\x1b[35m\x1b[103m .XMMMMMMMMMMMMMMMMMMMMMMMMK. \x1b[0m\n";
printf "\x1b[94m\x1b[102m kMMMMMMMMMMMMMMMMMMMMMMMd \x1b[0m\n";
printf "\x1b[94m\x1b[102m ;KMMMMMMMWXXWMMMMMMMMk. \x1b[0m\n";
printf "\x1b[94m\x1b[102m .cooc,. .,coo:. \x1b[0m\n";
And what I want to understand is how to define variables, and my idea was just to read the neofetch script, take what is needed and be done with it. @Trilby, obv that's another noob idea of mine.
Sorry that we had a missunderstanding, hope it makes more sense now and nobody got offended.
Have a good start in the week guys.
Peace
Offline
You can separate multiple ansi color codes by a semicolon, for example, your first printf could be as follows:
printf "\x1b[92;104m 'c. \x1b[0m\n"
You can also combine all the printfs into a single command:
#!/bin/sh
printf "\
\x1b[92;104m 'c. \x1b[0m
\x1b[92;104m ,xNMM. \x1b[0m
\x1b[92;104m .OMMMMo \x1b[0m
\x1b[92;104m OMMM0, \x1b[0m
\x1b[92;104m .;loddo:' loolloddol;. \x1b[0m
\x1b[92;104m cKMMMMMMMMMMNWMMMMMMMMMM0: \x1b[0m
\x1b[93;105m .KMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m
\x1b[93;105m XMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m
\x1b[33;101m ;MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m
\x1b[33;101m :MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m
\x1b[91;103m .MMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m
\x1b[91;103m kMMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m
\x1b[35;103m .XMMMMMMMMMMMMMMMMMMMMMMMMMMk \x1b[0m
\x1b[35;103m .XMMMMMMMMMMMMMMMMMMMMMMMMK. \x1b[0m
\x1b[94;102m kMMMMMMMMMMMMMMMMMMMMMMMd \x1b[0m
\x1b[94;102m ;KMMMMMMMWXXWMMMMMMMMk. \x1b[0m
\x1b[94;102m .cooc,. .,coo:. \x1b[0m
"
Then you may want to consider whether you really want the background color for the full line or just for the content as follows:
#!/bin/sh
printf "\
\x1b[92;104m'c.\x1b[0m
\x1b[92;104m,xNMM.\x1b[0m
\x1b[92;104m.OMMMMo\x1b[0m
\x1b[92;104mOMMM0,\x1b[0m
\x1b[92;104m.;loddo:' loolloddol;.\x1b[0m
\x1b[92;104mcKMMMMMMMMMMNWMMMMMMMMMM0:\x1b[0m
\x1b[93;105m.KMMMMMMMMMMMMMMMMMMMMMMMWd.\x1b[0m
\x1b[93;105mXMMMMMMMMMMMMMMMMMMMMMMMX.\x1b[0m
\x1b[33;101m;MMMMMMMMMMMMMMMMMMMMMMMM:\x1b[0m
\x1b[33;101m:MMMMMMMMMMMMMMMMMMMMMMMM:\x1b[0m
\x1b[91;103m.MMMMMMMMMMMMMMMMMMMMMMMMX.\x1b[0m
\x1b[91;103mkMMMMMMMMMMMMMMMMMMMMMMMMWd.\x1b[0m
\x1b[35;103m.XMMMMMMMMMMMMMMMMMMMMMMMMMMk\x1b[0m
\x1b[35;103m.XMMMMMMMMMMMMMMMMMMMMMMMMK.\x1b[0m
\x1b[94;102mkMMMMMMMMMMMMMMMMMMMMMMMd\x1b[0m
\x1b[94;102m;KMMMMMMMWXXWMMMMMMMMk.\x1b[0m
\x1b[94;102m.cooc,. .,coo:.\x1b[0m
"
Also, those colors codes are not in the right order to make anything like the classic apple logo reliably. On my system those colors are completely wrong and I don't recall adjusting the 16-255 colors (though I have previously, but I think I'm using my terminal defaults now.) EDIT: confirmed also on a tty, those values result in the background from top to bottom being blue, blue, purple, yellow, yellow, green while the apple logo should / would be green, green, yellow, orange, red, purple, blue.
While it's certainly subjective, I find something like this to be much more appealing:
#!/bin/sh
printf "\
\x1b[1;92m 'c. \x1b[0m
\x1b[1;92m ,xNMM. \x1b[0m
\x1b[1;92m .OMMMMo \x1b[0m
\x1b[1;92m OMMM0, \x1b[0m
\x1b[1;92m .;loddo:' loolloddol;. \x1b[0m
\x1b[1;92m cKMMMMMMMMMMNWMMMMMMMMMM0: \x1b[0m
\x1b[1;93m .KMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m
\x1b[1;93m XMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m
\x1b[1;33m ;MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m
\x1b[1;33m :MMMMMMMMMMMMMMMMMMMMMMMM: \x1b[0m
\x1b[1;91m .MMMMMMMMMMMMMMMMMMMMMMMMX. \x1b[0m
\x1b[1;91m kMMMMMMMMMMMMMMMMMMMMMMMMWd. \x1b[0m
\x1b[1;35m .XMMMMMMMMMMMMMMMMMMMMMMMMMMk \x1b[0m
\x1b[1;35m .XMMMMMMMMMMMMMMMMMMMMMMMMK. \x1b[0m
\x1b[1;94m kMMMMMMMMMMMMMMMMMMMMMMMd \x1b[0m
\x1b[1;94m ;KMMMMMMMWXXWMMMMMMMMk. \x1b[0m
\x1b[1;94m .cooc,. .,coo:. \x1b[0m
"
Last edited by Trilby (2022-11-20 19:35:00)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline