Replace a part of a string in zsh - linux

So, in my zshrc I have a blue prompt, and when the root user is used, it uses a version of the same prompt with the word blue changed to red
if [ $UID = 0 ]
then
export PS1="%B%F{red}[ %n#%m ]%f%b %F{white}:%f %F{yellow}%~%f %B%F{cyan}>%b%f "
export RPS1="%B%F{cyan}<%b%f "$(date +"%d/%m/%y ~ %H:%M:%S")""
else
export PS1="%B%F{blue}[ %n#%m ]%f%b %F{white}:%f %F{yellow}%~%f %B%F{cyan}>%b%f "
export RPS1="%B%F{cyan}<%b%f "$(date +"%d/%m/%y ~ %H:%M:%S")""
fi
I've done it like this for some time, but is it possible to just replace the word blue in PS1="%B%F{blue}..... with red? Or, the other way around?

Use a separate parameter to store you choice of color, then use that in the definition of PS1.
if [ $UID = 0 ]; then
color=red
else
color=blue
fi
PS1="%B%F{$color}[ %n#%m ]%f%b %F{white}:%f %F{yellow}%~%f %B%F{cyan}>%b%f "
RPS1="%B%F{cyan}<%b%f %D{%d/%m/%y ~ %T}" # You don't need to call date

Related

Check a c file output in Linux

I have 2 files .c which only contain a printf("x")
I am in bash script and i want to check if the values in the printf are for project1.c =20 and for project 2 =10,and then make some changes depending on the values.
How am i supposed to make the comparison in the if command?
This is what i have tried to do,not sure if it is right way.
for d in $1/*/*
do
gcc project1 project1.c
if[ ./project1 = 20 ];then
$project1 =30
else
$project1 =0
fi
gcc project2 project2.c
if[ ./project2 =10 ];then
$project2 = 70
else
$project2 = 0
fi
sum=$project1 + $project2
echo "project1 : $project1 project2: $project2 total grade: $sum" >> grades.txt
done
fi
Your invocation of gcc is wrong. You have to specify the output file:
gcc -o project1 project1.c
Next, in shell, variable substitution is a different process than assignment. So, you can't write $var=foo. The correct syntax is var=foo.
Then, space is a special character (it is used to separate arguments). So var=foo is not the same than var = foo. So, the correct syntax is:
project1=30
Next, in shell, the pattern $(command) is replaced by the result of command. So. I have to do:
if [ $(./project2) == 10 ]; then
Finally, you can do arithmetic using $((calculus)). So, you have to write:
sum=$(($project1 + $project2))

Is it possible to change the color of systemd (?) [FAILURE] [OK] or [SUCCESS] etc. in boot sequence?

My problem is, that any script / command in /etc/init.d seems to be overridden by something else or disregarded.
So I guess that this must be something to be configured in the kernel.
For example using /etc/init.d/some_script (This content is about what I want):
# Column number to place the status message
RES_COL=60
# Command to move out to the configured column number
MOVE_TO_COL="echo -en \\033[${RES_COL}G"
# Command to set the color to SUCCESS (Green)
SETCOLOR_SUCCESS="echo -en \\033[1;36m"
# Command to set the color to FAILED (Red)
SETCOLOR_FAILURE="echo -en \\033[1;31m"
# Command to set the color back to normal
SETCOLOR_NORMAL="echo -en \\033[0;39m"
# Function to print the SUCCESS status
echo_success() {
$MOVE_TO_COL
echo -n "["
$SETCOLOR_SUCCESS
echo -n $" OK "
$SETCOLOR_NORMAL
echo -n "]"
echo -ne "\r"
return 0
}
# Function to print the FAILED status message
echo_failure() {
$MOVE_TO_COL
echo -n "["
$SETCOLOR_FAILURE
echo -n $"FAILED"
$SETCOLOR_NORMAL
echo -n "]"
echo -ne "\r"
return 1
}
I've been grepping around inside the kernel- and other sources and inside the system but found nothing about that.
/drivers/tty/vt/vt.c seems to be some global config for the VT. That's not what I need.
I would be happy to receive a few tips.
Greetings
Jens
This OS uses systemd.
I just started my old computer with Mandriva 2009 and coloring worked out of the box. There is a file 'etc/sysconfig/init' in which I can set the color but here on Magaia 7.1 there is no such file. I only have /etc/init.d/functions which says:
"This file contains functions to be used by most or all shell scripts in the /etc/init.d directory."
There is a block in it showing the color configuration:
# Read in our configuration
if [ -z "${BOOTUP:-}" ]; then
if [ -f /etc/sysconfig/init ]; then
. /etc/sysconfig/init
else
# verbose ->> very (very!) old bootup look (prior to RHL-6.0?)
# color ->> default bootup look
# other ->> default bootup look without ANSI colors or positioning
BOOTUP=color
# Column to start "[ OK ]" label in:
RES_COL=60
# terminal sequence to move to that column:
MOVE_TO_COL="echo -en \\033[${RES_COL}G"
# Terminal sequence to set color to a 'success' (bright green):
SETCOLOR_SUCCESS="echo -en \\033[1;36m"
# Terminal sequence to set color to a 'failure' (bright red):
SETCOLOR_FAILURE="echo -en \\033[1;31m"
# Terminal sequence to set color to a 'warning' (bright yellow):
SETCOLOR_WARNING="echo -en \\033[1;33m"
# Terminal sequence to reset to the default color:
SETCOLOR_NORMAL="echo -en \\033[0;39m"
# Verbosity of logging:
LOGLEVEL=1
fi
if [ "$CONSOLETYPE" = "serial" ]; then
BOOTUP=serial
MOVE_TO_COL=
SETCOLOR_SUCCESS=
SETCOLOR_FAILURE=
SETCOLOR_WARNING=
SETCOLOR_NORMAL=
fi
But any changes do have no effect.
I tagged it linux-kernel because my guess was that this could be overriden by some kernel option or patch or config or someting like that.

Shell: Pass function with arguments as function argument

I'm working on a shell program to automatise my Arch (mandatory btw) installation. To make it more interactive, I've built the following function:
# READYN
# ARGS:
# - Yes/no question
# - Command to run if yes
# - Command to run if no
#
# Prompts the user with a yes/no question (with precedence for yes) and
# run an order if the answer is yes or another if it's no.
readyn () {
while :
do
local yn;
printf "%s? [Y/n]: " "$1";
read yn;
if [[ "$yn" =~ ^([yY][eE][sS]|[yY])?$ ]]; then
$2;
break;
elif [[ "$yn" =~ ^([nN][oO]|[nN])+$ ]]; then
$3;
break;
fi
done
}
I've succeeded in passing an "echo Hello World!" as an argument and having it run. I've also been able to pass another function. For example:
yayprompt () {
printf "yay is required to install %s.\n" "$1"
readyn "Install yay, the AUR manager" "yayinstall" ""
}
This calls yayinstall if yes and does nothing if no.
My problem comes with more complex functions, which are passed as arguments but are either not recognised or run when they're not supposed to. The problem comes with the following function:
# MANAGEPGK
# ARGS:
# - Package name
# - Package variable
# - Yay required
#
# Checks if the package is added to the pkglist to either add or remove it.
# If yay is required to install it, it prompts the user whether they wish
# to install yay or don't install the package (if yay is not installed).
# This functions DOES NOT prompt any installation options on the user. To
# do this, use PROMPTPKG.
managepkg () {
local pkgvar=$2
if [ $pkgvar == 0 ]; then
if [ $3 == 1 ] && [ $yay == 0 ]; then
yayprompt;
fi
if [ $3 == 0 ] || [ $yay == 1 ]; then
addpkg "$1";
pkgvar=1;
fi
else
rmpkg "$1";
pkgvar=0;
fi
echo "$pkgvar";
}
For it to work properly, it has to (or at least I've had to) be called like this:
dewm_cinnamon=$(managepkg cinnamon $dewm_cinnamon 0)
Now, I'm trying to pass it as an argument to readyn, but I'm having these outputs depending on the format (I'm always answering yes as empty string:
Simple quotes:
readyn "Install gaps" \
'dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)' \
'dewm_i3=$(managepkg i3-wm $dewm_i3 0)';
Install gaps? [Y/n]:
./architup.sh: line 341: dewm_i3gaps=$(managepkg: command not found
Double quotes:
readyn "Install gaps" \
"dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)" \
"dewm_i3=$(managepkg i3-wm $dewm_i3 0)";
Install gaps? [Y/n]:
./architup.sh: line 341: dewm_i3gaps=1: command not found
Dollar enclosed: (This one runs both commands as seen in cat pkglist)
readyn "Install gaps" \
$(dewm_i3gaps=$(managepkg i3-gaps $dewm_i3gaps 0)) \
$(dewm_i3=$(managepkg i3-wm $dewm_i3 0));
Install gaps? [Y/n]:
Install compton? [Y/n]: ^C
Documents/Repositories/architup took 5s
➜ cat pkglist
i3-gaps
i3-wm
What syntax should I use to have readyn run only one command based on the user input?
Thank you!
Function arguments are just strings. A better design IMHO is to simply have readyn return true (zero) for "yes" and false otherwise, and have the calling code implement any conditional logic based on that.
readyn () {
read -p "$#"
case $REPLY in
[Yy] | [Yy][Ee][Ss]) return 0;;
esac
return 1
}
readyn "Are you ready San Antonio?" &&
rock and roll
if readyn "Let me hear you say yeah"; then
echo "Let's go!"
else
echo "If you feel mellow, get outta here"
fi
(With apologies to rock concerts everywhere,)

Bash prompt with the last exit code

I've been trying to customize my Bash prompt so that it will look like
[feralin#localhost ~]$ _
with colors. I managed to get constant colors (the same colors every time I see the prompt), but I want the username ('feralin') to appear red, instead of green, if the last command had a nonzero exit status. I came up with:
\e[1;33m[$(if [[ $? == 0 ]]; then echo "\e[0;31m"; else echo "\e[0;32m"; fi)\u\e[m#\e[1;34m\h \e[0;35m\W\e[1;33m]$ \e[m
However, from my observations, the $(if ...; fi) seems to be evaluated once, when the .bashrc is run, and the result is substituted forever after. This makes the name always green, even if the last exit code is nonzero (as in, echo $?). Is this what is happening? Or is it simply something else wrong with my prompt? Long question short, how do I get my prompt to use the last exit code?
As you are starting to border on a complex PS1, you might consider using PROMPT_COMMAND. With this, you set it to a function, and it will be run after each command to generate the prompt.
You could try the following in your ~/.bashrc file:
PROMPT_COMMAND=__prompt_command # Function to generate PS1 after CMDs
__prompt_command() {
local EXIT="$?" # This needs to be first
PS1=""
local RCol='\[\e[0m\]'
local Red='\[\e[0;31m\]'
local Gre='\[\e[0;32m\]'
local BYel='\[\e[1;33m\]'
local BBlu='\[\e[1;34m\]'
local Pur='\[\e[0;35m\]'
if [ $EXIT != 0 ]; then
PS1+="${Red}\u${RCol}" # Add red if exit code non 0
else
PS1+="${Gre}\u${RCol}"
fi
PS1+="${RCol}#${BBlu}\h ${Pur}\W${BYel}$ ${RCol}"
}
This should do what it sounds like you want. Take a look a my bashrc's sub file if you want to see all the things I do with my __prompt_command function.
If you don't want to use the prompt command there are two things you need to take into account:
getting the value of $? before anything else. Otherwise it'll be overridden.
escaping all the $'s in the PS1 (so it's not evaluated when you assign it)
Working example using a variable
PS1="\$(VALU="\$?" ; echo \$VALU ; date ; if [ \$VALU == 0 ]; then echo zero; else echo nonzero; fi) "
Working example without a variable
Here the if needs to be the first thing, before any command that would override the $?.
PS1="\$(if [ \$? == 0 ]; then echo zero; else echo nonzero; fi) "
Notice how the \$() is escaped so it's not executed right away, but each time PS1 is used. Also all the uses of \$?.
Compact solution:
PS1='... $(code=${?##0};echo ${code:+[error: ${code}]})'
This approach does not require PROMPT_COMMAND (apparently this can be slower sometimes) and prints [error: <code>] if the exit code is non-zero, and nothing if it's zero:
... > false
... [error: 1]> true
... >
Change the [error: ${code}] part depending on your liking, with ${code} being the non-zero code to print.
Note the use of ' to ensure the inline $() shell gets executed when PS1 is evaluated later, not when the shell is started.
As bonus, you can make it colorful in red by adding \e[01;31m in front and \e[00m after to reset:
PS1='... \e[01;31m$(code=${?##0};echo ${code:+[error: ${code}]})\e[00m'
--
How it works:
it uses bash parameter substitution
first, the ${?##0} will read the exit code $? of the previous command
the ## will remove any 0 pattern from the beginning, effectively making a 0 result an empty var (thanks #blaskovicz for the trick)
we assign this to a temporary code variable as we need to do another substitution, and they can't be nested
the ${code:+REPLACEMENT} will print the REPLACEMENT part only if the variable code is set (non-empty)
this way we can add some text and brackets around it, and reference the variable again inline: [error: ${code}]
I wanted to keep default Debian colors, print the exact code, and only print it on failure:
# Show exit status on failure.
PROMPT_COMMAND=__prompt_command
__prompt_command() {
local curr_exit="$?"
local BRed='\[\e[0;91m\]'
local RCol='\[\e[0m\]'
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u#\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
if [ "$curr_exit" != 0 ]; then
PS1="[${BRed}$curr_exit${RCol}]$PS1"
fi
}
The following provides a leading green check mark when the exit code is zero and a red cross in all other cases. The remainder is a standard colorized prompt. The printf statements can be modified to present the two states that were originally requested.
PS1='$(if [ $? -eq 0 ]; then printf "\033[01;32m""\xE2\x9C\x93"; else printf "\033[01;31m""\xE2\x9C\x95"; fi) \[\e[00;32m\]\u#\h\[\e[00;30m\]:\[\e[01;33m\]\w\[\e[01;37m\]\$ '
Why didn't I think about that myself? I found this very interesting and added this feature to my 'info-bar' project. Eyes will turn red if the last command failed.
#!/bin/bash
eyes=(O o ∘ ◦ ⍤ ⍥) en=${#eyes[#]} mouth='_'
face () { # gen random face
[[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
if [[ $1 ]]; then printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}"
else printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
fi
}
info () { error=$?
[[ -d .git ]] && { # If in git project folder add git status to info bar output
git_clr=('GIT' $(git -c color.ui=always status -sb)) # Colored output 4 info
git_tst=('GIT' $(git status -sb)) # Simple output 4 test
}
printf -v line "%${COLUMNS}s" # Set border length
date=$(printf "%(%a %d %b %T)T") # Date & time 4 test
test=" O_o $PWD ${git_tst[*]} $date o_O " # Test string
step=$[$COLUMNS-${#test}]; [[ $step -lt 0 ]] && step=0 # Count spaces
line="$GRN${line// /-}$DEF\n" # Create lines
home="$BLD$BLU$PWD$DEF" # Home dir info
date="$DIM$date$DEF" # Colored date & time
#------+-----+-------+--------+-------------+-----+-------+--------+
# Line | O_o |homedir| Spaces | Git status | Date| o_O | Line |
#------+-----+-------+--------+-------------+-----+-------+--------+
printf "$line $(face) $home %${step}s ${git_clr[*]} $date $(face) \n$line" # Final info string
}
PS1='${debian_chroot:+($debian_chroot)}\n$(info)\n$ '
case "$TERM" in xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)} $(face 1) \w\a\]$PS1";;
esac
Improved demure answer:
I think this is important because the exit status is not always 0 or 1.
if [ $EXIT != 0 ]; then
PS1+="${Red}${EXIT}:\u${RCol}" # Add red if exit code != 0
else
PS1+="${Gre}${EXIT}:\u${RCol}" # Also displays exit status
fi
To preserve the original prompt format (not just colors),
you could append following to the end of file ~/.bashrc:
PS1_ORIG=$PS1 # original primary prompt value
PROMPT_COMMAND=__update_prompt # Function to be re-evaluated after each command is executed
__update_prompt() {
local PREVIOUS_EXIT_CODE="$?"
if [ $PREVIOUS_EXIT_CODE != 0 ]; then
local RedCol='\[\e[0;31m\]'
local ResetCol='\[\e[0m\]'
local replacement="${RedCol}\u${ResetCol}"
# Replace username color
PS1=${PS1_ORIG//]\\u/]$replacement}
## Alternative: keep same colors, append exit code
#PS1="$PS1_ORIG[${RedCol}error=$PREVIOUS_EXIT_CODE${ResetCol}]$ "
else
PS1=$PS1_ORIG
fi
}
See also the comment about the alternative approach that preserves username color and just appends an error code in red to the end of the original prompt format.
You can achieve a similar result to include a colored (non-zero) exit code in a prompt, without using subshells in the prompt nor prompt_command.
You color the exit code portion of the prompt, while having it only appear when non-zero.
Core 2$ section of the prompt: \\[\\033[0;31;4m\\]\${?#0}\\[\\033[0;33m\\]\$ \\[\\033[0m\\]
Key elements:
return code, if not 0: \${?#0} (specificly "removes prefix of 0")
change color without adding to calculated prompt-width: \\[\\033[0;31m\\]
\\[ - begin block
\\033 - treat as 0-width, in readline calculations for cmdline editing
[0;31;4m - escape code, change color, red fg, underline
\\] - end block
Components:
\\[\\033[0;31;4m\\] - set color 0;31m fg red, underline
\${?#0} - display non-zero status (by removing 0 prefix)
\\[\\033[0;33m\\] - set color 0;33m fg yellow
\$ - $ or # on EUID
\\[\\033[0m\\] - reset color
The full PS1 I use (on one host):
declare -x PS1="\\[\\033[0;35m\\]\\h\\[\\033[1;37m\\] \\[\\033[0;37m\\]\\w \\[\\033[0;33m\\]\\[\\033[0;31;4m\\]\${?#0}\\[\\033[0;33m\\]\$ \\[\\033[0m\\]"
Note: this addresses a natural extension to this question, in a more enduring way then a comment.
Bash
function my_prompt {
local retval=$?
local field1='\u#\h'
local field2='\w'
local field3='$([ $SHLVL -gt 1 ] && echo \ shlvl:$SHLVL)$([ \j -gt 0 ] && echo \ jobs:\j)'"$([ ${retval} -ne 0 ] && echo \ exit:$retval)"
local field4='\$'
PS1=$'\n'"\e[0;35m${field1}\e[m \e[0;34m${field2}\e[m\e[0;31m${field3}\e[m"$'\n'"\[\e[0;36m\]${field4}\[\e[m\] "
}
PROMPT_COMMAND="my_prompt; ${PROMPT_COMMAND}"
Zsh
PROMPT=$'\n''%F{magenta}%n#%m%f %F{blue}%~%f%F{red}%(2L. shlvl:%L.)%(1j. jobs:%j.)%(?.. exit:%?)%f'$'\n''%F{cyan}%(!.#.$)%f '
Images of prompt

Grub 2, changing shift button

I'm new to linux and bash, so I don't know what am I doing wrong. I set up grub to don't show, and show after pushing shift for 3 seconds. This worked fine. Then I changed line in 30_os-prober (as you can see underneath) which contained 'shift' to 'F11' as I read here: http://www.gnu.org/software/grub/manual/grub.html (13.3.33). Now when I press F11 nothing happens, and when I press shift I can see 'Grub is loading', then default OS (Ubuntu) loads without showing grub menu.
This is part of my /etc/default/grub content:
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
GRUB_DEFAULT="Custom Menu"
GRUB_HIDDEN_TIMEOUT=1
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="splash"
GRUB_CMDLINE_LINUX=" splash vga=799 quiet"
and this is (IMHO) crucial part, from /etc/grub.d/30_os-prober:
adjust_timeout () {
#if [ "x${found_other_os}" = "x" ] ; then
if [ "x${GRUB_HIDDEN_TIMEOUT}" != "x" ] ; then
if [ "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
verbose=
else
verbose=" --verbose"
fi
if [ "x${GRUB_HIDDEN_TIMEOUT}" = "x0" ] ; then
cat <<EOF
if [ \${timeout} != -1 ]; then
if keystatus; then
if keystatus --F11; then << There I changed shift to F11
set timeout=-1
else
set timeout=0
fi
else
if sleep$verbose --interruptible 3 ; then
set timeout=0
fi
fi
fi
EOF
else
cat << EOF
if [ \${timeout} != -1 ]; then
if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT} ; then
set timeout=0
fi
fi
EOF
fi
fi
#fi
}
Thank you.
The keystatus documentation at the link you provided (and other keystatus documentation that I've come across) indicates that it accepts only --shift --ctrl or --alt as key-specific parameters. Perhaps it does not work for other keys such as F11.
The other thing to be aware of is that keystatus apparently does not work on all platforms. When that is the case, your first keystatus call will return false and the rest of the keystatus conditional logic will be skipped.

Resources