I am trying to use whether or not a line contains a date as a condition for an if statement:
if [grep -n -v '[0-9][0-9][0-9][0-9]' $line |wc -l==0]
then
...
The above returns an error. I don't necessarily need to use grep. The line processed by grep would look like:
1984 Dan Marino QB Miami Dolphins
Any help is appreciated.
if [[ $(echo $line | grep -q '[0-9][0-9][0-9][0-9]') ]]; then
# do something
fi
You can check this using bash built-ins:
re='\b[[:digit:]]{4}\b'
if [[ $line =~ $re ]] ; then
echo ok;
fi
[grep -n -v '[0-9][0-9][0-9][0-9]' $line |wc -l==0]
problem 1: [(space).....(space)] you need those spaces
problem 2: there is no [ foo==bar ] you can do something like [ $(echo "0") = "0" ] or [[ $(echo "0") == 0 ]] here the $(echo "0") is an example, you should fill with your commands.
You can just call grep with -q option and check the return value:
if [ $(grep -qv '[0-9][0-9][0-9][0-9]' $line) -eq 0 ]; then
# ...
fi
Use command substitution and proper bash syntax.
[[ "`grep -n -v '[0-9][0-9][0-9][0-9]' $line | wc -l`" -eq 0 ]]
Related
I trying to make script that shows volume level of active volume sink. Here is code
#!/bin/bash
active_sink=$(pacmd list-sinks |awk '/* index:/{print $3}')
muted=$(pactl list sinks | perl -000ne 'if(/#${active_sink}/){/(Mute:.*)/; print "$1\n"}' | cut -f2 -d':' | cut -f2 -d' ')
vol=$(pactl list sinks | perl -000ne 'if(/#${active_sink}/){/(Volume:.*)/; print "$1\n"}' | cut -f1 -d'%' | tail -c 3
)
if [[ $muted = "no" ]]; then
if [[ $vol -ge 65 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-high.svg
echo "$vol%"
elif [[ $vol -ge 40 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-medium.svg
echo "$vol%"
elif
[[ $vol -ge 0 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-low.svg
echo "$vol%"
fi
else
echo ~/.config/tint2/executors/icons/audio-volume-muted.svg
echo "muted"
fi
I can't get this script to work, always get "muted".
I finally makes this thing to work, thanks #markp-fuso.
The problem was with perl and ${active_sink}.
Final code that work with corrected muted and vol
#!/bin/bash
active_sink=$(pacmd list-sinks | awk '/* index:/{print $3}')
muted=$(pactl list sinks | grep -A14 -P "(\#|№)$active_sink" | awk '/Mute:/{print $2}')
vol=$(pactl list sinks | grep -A14 -P "(\#|№)$active_sink" | awk '/Volume: front-left:/{print $5}' | cut -f1 -d'%')
if [[ $muted = "no" ]]; then
if [[ $vol -ge 65 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-high.svg
echo "$vol%"
elif [[ $vol -ge 40 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-medium.svg
echo "$vol%"
elif
[[ $vol -ge 0 ]]; then
echo ~/.config/tint2/executors/icons/audio-volume-low.svg
echo "$vol%"
fi
else
echo ~/.config/tint2/executors/icons/audio-volume-muted.svg
echo "muted"
fi
My Bash-Script has to do something different, according of the beginning of a Variable.
When I run the following script:
#!/bin/bash
line="__B something"
if [ -n $(echo "$line" | grep "^__A") ]; then
echo "Line __A"
elif [ -n $(echo "$line" | grep "^__B") ]; then
echo "Line __B"
elif [ -n $(echo "$line" | grep "^__C") ]; then
echo "Line __C"
elif [ -n $(echo "$line" | grep "^__D") ]; then
echo "Line __D"
elif [ -n $(echo "$line" | grep "^__E") ]; then
echo "Line __E"
elif [ $(echo "$line" | grep "^__F") ]; then
echo -n "Line __F"
else
echo "something other"
fi
Bash does not recognize that the String start's with __B.:
Output is:
Line __A
What's wrong with my Script?
Thank you for your help!
If you run your script using the xtrace option than you can see what is happening:
bash -x your-script
+ line='__B something'
++ echo '__B something'
++ grep '^__A'
+ '[' -n ']'
+ echo 'Line __A'
Line __A
Because you use the old test built-in (otherwise known as [) the expansion is done but results in nothing to test except the -n. Using the [[ keyword will quote things correctly:
bash -x your-script
+ line='__B something'
++ echo '__B something'
++ grep '^__A'
+ [[ -n '' ]]
++ echo '__B something'
++ grep '^__B'
+ [[ -n __B something ]]
+ echo 'Line __B'
Line __B
However, using the external program grep is a waste. Recent versions of bash have regular expressions (REs) built-in (using the binding operator =~) but you don't need REs in this case, simple globbing will do:
#!/bin/bash
line="__B something"
if [[ $line == __A* ]]; then
echo "Line __A"
elif [[ $line == __B* ]]; then
echo "Line __B"
elif [[ $line == __C* ]]; then
echo "Line __C"
elif [[ $line == __D* ]]; then
echo "Line __D"
elif [[ $line == __E* ]]; then
echo "Line __E"
elif [[ $line == __F* ]]; then
echo -n "Line __F"
else
echo "something other"
fi
I believe it has to do with the subtleties of the difference between using [[ and [ in bash if conditionals.
You can either use [[ and ]] everywhere (seems to work), e.g.
if [[ -n $(echo "$line" | grep "^__A") ]]; then
echo "Line __A"
or you can quote the subshell like this
if [ -n "$(echo '$line' | grep '^__A')" ]; then
echo "Line __A"
[[ has fewer surprises and is generally safer to use. But it is not
portable - Posix doesn't specify what it does and only some shells
support it (beside bash, i heard ksh supports it too). For example,
you can do
[[ -e $b ]]
to test whether a file exists. But with [, you have to quote $b,
because it splits the argument and expands things like "a*" (where [[
takes it literally). That has also to do with how [ can be an external
program and receives its argument just normally like every other
program (although it can also be a builtin, but then it still has not
this special handling).
according to this answer here on stackoverflow. So in your case, most likely bash is separating your string on a space and that is having some side effects.
I am trying to pipe information from my workspaces into another command, and because each workspace contains the same information, with only a different number to identify it, I have written 10 functions where the only difference is one character inside some variable names. I feel like this can be greatly simplified, but I cannot figure out how to get any sort of loop working in my situation.
All here is my script containing the 10 functions:
#!/bin/bash
# Include config file.
. $(dirname $0)/config
getWorkspaceInfo(){
filledWorkspaces=$(i3-msg -t get_workspaces | grep -Po '"'"name"'"\s*:\s*"\K([^"]*)')
currentWorkspace=$(i3-msg -t get_outputs | sed 's/.*"current_workspace":"\([^"]*\)".*/\1/')
}
# Determine the status of each workspace. Current is green, unfocused is white, empty is grey.
workspace1(){
if [[ ${currentWorkspace} -eq 1 ]]; then
workspace1Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "1") == "" ]]; then
workspace1Color=${grey}
else
workspace1Color=${foreground}
fi
echo "%{F${workspace1Color}}${workspace1Name}"
}
workspace2(){
if [[ ${currentWorkspace} -eq 2 ]]; then
workspace2Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "2") == "" ]]; then
workspace2Color=${grey}
else
workspace2Color=${foreground}
fi
echo "%{F${workspace2Color}}${workspace2Name}"
}
workspace3(){
if [[ ${currentWorkspace} -eq 3 ]]; then
workspace3Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "3") == "" ]]; then
workspace3Color=${grey}
else
workspace3Color=${foreground}
fi
echo "%{F${workspace3Color}}${workspace3Name}"
}
workspace4(){
if [[ ${currentWorkspace} -eq 4 ]]; then
workspace4Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "4") == "" ]]; then
workspace4Color=${grey}
else
workspace4Color=${foreground}
fi
echo "%{F${workspace4Color}}${workspace4Name}"
}
workspace5(){
if [[ ${currentWorkspace} -eq 5 ]]; then
workspace5Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "5") == "" ]]; then
workspace5Color=${grey}
else
workspace5Color=${foreground}
fi
echo "%{F${workspace5Color}}${workspace5Name}"
}
workspace6(){
if [[ ${currentWorkspace} -eq 6 ]]; then
workspace6Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "6") == "" ]]; then
workspace6Color=${grey}
else
workspace6Color=${foreground}
fi
echo "%{F${workspace6Color}}${workspace6Name}"
}
workspace7(){
if [[ ${currentWorkspace} -eq 7 ]]; then
workspace7Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "7") == "" ]]; then
workspace7Color=${grey}
else
workspace7Color=${foreground}
fi
echo "%{F${workspace7Color}}${workspace7Name}"
}
workspace8(){
if [[ ${currentWorkspace} -eq 8 ]]; then
workspace8Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "8") == "" ]]; then
workspace8Color=${grey}
else
workspace8Color=${foreground}
fi
echo "%{F${workspace8Color}}${workspace8Name}"
}
workspace9(){
if [[ ${currentWorkspace} -eq 9 ]]; then
workspace9Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "9") == "" ]]; then
workspace9Color=${grey}
else
workspace9Color=${foreground}
fi
echo "%{F${workspace9Color}}${workspace9Name}"
}
workspace10(){
if [[ ${currentWorkspace} -eq 10 ]]; then
workspace10Color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "10") == "" ]]; then
workspace10Color=${grey}
else
workspace10Color=${foreground}
fi
echo "%{F${workspace10Color}}${workspace10Name}"
}
# Pipe functions to the bar infinitely.
while true; do
getWorkspaceInfo
echo "%{c}$(workspace1)${separator}$(workspace2)${separator}$(workspace3)${separator}$(workspace4)${separator}$(workspace5)${separator}$(workspace6)${separator}$(workspace7)${separator}$(workspace8)${separator}$(workspace9)${separator}$(workspace10)"
done | lemonbar -g ${panelWidth}x${panelHeight}+${panelX}+${bottomPanelY} -f "${font}" -f "${iconFont}" -B "${background}" -F "${foreground}" -p -d | \
while true; do read line; eval $line; done &
Here is the config file that I am importing:
#!/bin/bash
# Outside sources
xres="$HOME/.Xresources"
i3config="$HOME/.config/i3/config"
# Fetch information from Xresources
background=$(cat ${xres} | grep -i background | tail -c 8)
foreground=$(cat ${xres} | grep -i foreground | tail -c 8)
black=$(cat ${xres} | grep -i color0 | tail -c 8)
grey=$(cat ${xres} | grep -i color8 | tail -c 8)
red=$(cat ${xres} | grep -i color9 | tail -c 8)
green=$(cat ${xres} | grep -i color10 | tail -c 8)
yellow=$(cat ${xres} | grep -i color11 | tail -c 8)
blue=$(cat ${xres} | grep -i color12 | tail -c 8)
magenta=$(cat ${xres} | grep -i color13 | tail -c 8)
cyan=$(cat ${xres} | grep -i color14 | tail -c 8)
white=$(cat ${xres} | grep -i color15 | tail -c 8)
# Fetch information from i3 config
gapSize=$(cat ${i3config} | grep -i "gaps inner" | awk '{print $3}')
# Workspace names -- independant from i3 config -- workspaces in i3 config should be named numbers 1-10.
workspace1Name="Web Browser"
workspace2Name="Terminal"
workspace3Name="Text Editor"
workspace4Name="Unspecified"
workspace5Name="Unspecified"
workspace6Name="Unspecified"
workspace7Name="Unspecified"
workspace8Name="Unspecified"
workspace9Name="Messenger"
workspace10Name="Music Player"
# Fonts
font="InputSans-10"
iconFont="FontAwesome"
separator="%{F$foreground} |│| "
# Panel size
screenWidth=$(xrandr | grep 'Screen 0'| awk '{print $8}')
screenHeight=$(xrandr | grep 'Screen 0' | awk '{print $10}' | tr -d ",")
panelHeight=$((${gapSize} * 2))
panelWidth=$((${screenWidth} - ${panelHeight}))
panelX=${gapSize}
topPanelY=${gapSize}
bottomPanelY=$((${screenHeight} - ${panelHeight} - ${gapSize}))
Well, the simplest fix is to write something like:
function all_10_workspaces () {
local i
for i in {1..10} ; do
local workspaceNameVar="workspace${i}Name"
local workspaceName="${!workspaceNameVar}"
local color
if (( currentWorkspace == 1 )) ; then
color=$green
elif grep -w -q "$i" <<< "$filledWorkspaces" ; then
color=$foreground
else
color=$grey
fi
echo "%{F$color}$workspaceName"
done
}
. . . however, you should really consider using arrays instead. For example:
workspaceNames=(
'' # 0 (no such workspace)
'Web Browser' # 1
Terminal # 2
'Text Editor' # 3
Unspecified # 4
Unspecified # 5
Unspecified # 6
Unspecified # 7
Unspecified # 8
Messenger # 9
'Music Player' # 10
)
Then, for example, workspace #7 is named "${workspaceNames[7]}", and given a variable i, workspace #i is named "${workspaceNames[i]}".
Something like this, perhaps?
workspaceCount=10
while true; do
# Output will look like "%{c}$(workspace1Color)${separator}$(workspace2Color)${separator}...."
# This is what is sent before the first item in each line
itemSep="%{c}"
for i in {1..$workspaceCount}; do
if [ ${currentWorkspace} -eq $i ]; then
color="${green}"
elif [[ $(echo ${filledWorkspaces} | grep -w "1") == "" ]]; then
color="${grey}"
else
color="${foreground}"
fi
echo -n "${itemSep}${color}"
itemSep="${separator}"
done
echo # Send LF after all items
done
I figured out a way to get what I wanted using ideas from both ruakh and Phil Freed as well as something I came up with on my own. This may not be the shortest or most efficient way to solve the problem, but it is much shorter than having 10 separate functions.
#!/bin/bash
# Include config file.
. $(dirname $0)/config
getWorkspaceInfo(){
filledWorkspaces=$(i3-msg -t get_workspaces | grep -Po '"'"name"'"\s*:\s*"\K([^"]*)')
currentWorkspace=$(i3-msg -t get_outputs | sed 's/.*"current_workspace":"\([^"]*\)".*/\1/')
}
# Determine the status of each workspace. Current is green, unfocused is white, empty is grey.
workspaces(){
workspaces=""
currentSeparator="${separator}"
for i in {1..10} ; do
if [[ ${currentWorkspace} -eq ${i} ]]; then
color=${green}
elif [[ $(echo ${filledWorkspaces} | grep -w "${i}") == "" ]]; then
color=${grey}
else
color=${foreground}
fi
if [[ ${i} -eq 10 ]]; then
currentSeparator=""
fi
workspaces+="%{F$color}${workspaceNames[i]}${currentSeparator}"
done
echo "${workspaces}"
}
# Pipe functions to the bar infinitely.
while true; do
getWorkspaceInfo
echo "%{c}$(workspaces)"
done | lemonbar -g ${panelWidth}x${panelHeight}+${panelX}+${bottomPanelY} -f "${font}" -f "${iconFont}" -B "${background}" -F "${foreground}" -p -d | \
while true; do read line; eval $line; done &
To explain what it does as simply as possible:
Loop through all 10 workspaces, adding what would have been the output of a single function to the end of a new variable. Since I cannot add a separator between each function call anymore, I simply added the separator to the end of the echo, making sure that no separator is added to the last workspace by using a for loop, which sets the separator variable to null.
enter image description hereI was trying to see how a shell scripts work and how to run them, so I toke some sample code from a book I picked up from the library called "Wicked Cool Shell Scripts"
I re wrote the code verbatim, but I'm getting an error from Linux, which I compiled the code on saying:
'd.sh: line 3: syntax error near unexpected token `{
'd.sh: line 3:`gmk() {
Before this I had the curly bracket on the newline but I was still getting :
'd.sh: line 3: syntax error near unexpected token
'd.sh: line 3:`gmk()
#!/bin/sh
#format directory- outputs a formatted directory listing
gmk()
{
#Give input in Kb, output converted to Kb, Mb, or Gb for best output format
if [$1 -ge 1000000]; then
echo "$(scriptbc -p 2 $1/1000000)Gb"
elif [$1 - ge 1000]; then
echo "$$(scriptbc -p 2 $1/1000)Mb"
else
echo "${1}Kb"
fi
}
if [$# -gt 1] ; then
echo "Usage: $0 [dirname]" >&2; exit 1
elif [$# -eq 1] ; then
cd "$#"
fi
for file in *
do
if [-d "$file"] ; then
size = $(ls "$file"|wc -l|sed 's/[^[:digit:]]//g')
elif [$size -eq 1] ; then
echo "$file ($size entry)|"
else
echo "$file ($size entries)|"
fi
else
size ="$(ls -sk "$file" | awk '{print $1}')"
echo "$file ($(gmk $size))|"
fi
done | \
sed 's/ /^^^/g' |\
xargs -n 2 |\
sed 's/\^\^\^/ /g' | \
awk -F\| '{ printf "%39s %-39s\n", $1, $2}'
exit 0
if [$#-gt 1]; then
echo "Usage :$0 [dirname]" >&2; exit 1
elif [$# -eq 1]; then
cd "$#"
fi
for file in *
do
if [ -d "$file" ] ; then
size =$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')
if [ $size -eq 1 ] ; then
echo "$file ($size entry)|"
else
echo "$file ($size entries)|"
fi
else
size ="$(ls -sk "$file" | awk '{print $1}')"
echo "$file ($(convert $size))|"
fi
done | \
sed 's/ /^^^/g' | \
xargs -n 2 | \
sed 's/\^\^\^/ /g' | \
awk -F\| '{ printf "%-39s %-39s\n", $1, $2 }'
exit 0
sh is very sensitive to spaces. In particular assignment (no spaces around =) and testing (must have spaces inside the [ ]).
This version runs, although fails on my machine due to the lack of scriptbc.
You put an elsif in a spot where it was supposed to be if.
Be careful of column alignment between starts and ends. If you mismatch them it will easily lead you astray in thinking about how this works.
Also, adding a set -x near the top of a script is a very good way of debugging what it is doing - it will cause the interpreter to output each line it is about to run before it does.
#!/bin/sh
#format directory- outputs a formatted directory listing
gmk()
{
#Give input in Kb, output converted to Kb, Mb, or Gb for best output format
if [ $1 -ge 1000000 ]; then
echo "$(scriptbc -p 2 $1/1000000)Gb"
elif [ $1 -ge 1000 ]; then
echo "$(scriptbc -p 2 $1/1000)Mb"
else
echo "${1}Kb"
fi
}
if [ $# -gt 1 ] ; then
echo "Usage: $0 [dirname]" >&2; exit 1
elif [ $# -eq 1 ] ; then
cd "$#"
fi
for file in *
do
if [ -d "$file" ] ; then
size=$(ls "$file"|wc -l|sed 's/[^[:digit:]]//g')
if [ $size -eq 1 ] ; then
echo "$file ($size entry)|"
else
echo "$file ($size entries)|"
fi
else
size="$(ls -sk "$file" | awk '{print $1}')"
echo "$file ($(gmk $size))|"
fi
done | \
sed 's/ /^^^/g' |\
xargs -n 2 |\
sed 's/\^\^\^/ /g' | \
awk -F\| '{ printf "%39s %-39s\n", $1, $2}'
exit 0
By the way, with respect to the book telling you to modify your PATH variable, that's really a bad idea, depending on what exactly it advised you to do. Just to be clear, never add your current directory to the PATH variable unless you intend on making that directory a permanent location for all of your scripts etc. If you are making this a permanent location for your scripts, make sure you add the location to the END of your PATH variable, not the beginning, otherwise you are creating a major security problem.
Linux and Unix do not add your current location, commonly called your PWD, or present working directory, to the path because someone could create a script called 'ls', for example, which could run something malicious instead of the actual 'ls' command. The proper way to execute something in your PWD, is to prepend it with './' (e.g. ./my_new_script.sh). This basically indicates that you really do want to run something from your PWD. Think of it as telling the shell "right here". The '.' actually represents your current directory, in other words "here".
Why I have a integer expression expected error with this:
at=`echo $1 | grep -q "#"`
if [ $at -ne 0 ]; then
echo "blabla"
else
echo "bloblo"
fi
$at is set, and the test working fine outside the script
When testing the result of grep -q, you want to test $? not the output of grep, which will be empty
at=$(echo "$1" | grep -q "#")
if [ $? -ne 0 ]; then ...
or simply
if echo "$1" | grep -q "#"; then ...
or, more bash-ly
if grep -q "#" <<< "$1"; then ...
or, without calling grep:
if [[ "$1" == *#* ]]; then ...
or
case "$1" in
*#*) echo "match" ;;
*) echo "no match" ;;
esac
-ne is for comparing integers. Use != to compare strings.