bash Regular Expression in if Statement - regex

I am stumped at the error I am getting from a script I'm trying to run to suspend my machine. I am trying to use a regex in an elif statement to suspend my machine after a specific time period.
#!/bin/bash
echo "When would you like to suspend the machine?"
read "sustime"
if [ "$sustime" = "now" ]
then
sudo pm-suspend
elif [[ "$sustime" =~ [0-9]*[smhd] ]]
then
time=`expr "$sustime" : '\([0-9]+)\)'`
ttype=`expr "$sustime" : '.*\([smhd]\)'`
sudo sleep $time$ttype ; sudo pm-suspend
else
echo "Please enter either [now] or [#s|m|h|d]"
fi
The code doesn't work on the elif line, for example if I input 5s, the output of the script is:
$ sh dbussuspend.sh
When would you like to suspend the machine?
5s
dbussuspend.sh: 10: dbussuspend.sh: [[: not found
Please enter either [now] or [#s|m|h|d]
However, it should read that I've entered the string 5s run the code block under elif. I've actually tried any regex in place of [0-9]*[smhd], all with the same error.

this problem is not caused by your script, but by how you're invoking it:
sh dbussuspend.sh
should be:
bash dbussuspend.sh
bash know how to [[, but sh doesn't...
better still, do as Gordon Davisson suggests. do this once:
chmod +x dbussuspend.sh
and thenceforth, invoke like this:
./dbussuspend.sh
additionally, Etan Reisner and chepner question your use of expr, and laurel your bash regex. GNU coreutils sleep supports e.g. sleep 30s, sleep 2m, sleep 1h. check this on your system with man sleep. if so, then this will work:
elif [[ "$sustime" =~ ^[0-9]+[smhd]$ ]]
then
sudo sleep $sustime ; sudo pm-suspend
(^ and $ in ^[0-9]+[smhd]$ to match the start and end of the string and prevent matching e.g. "uzeifue1sziufzr".)

Related

Using regex on bash script to identify option parameters

I'm fairly new to this topic and I apologize if this question is irrelevant. I searched the website thoroughly but didn't find an answer.
I'm making this shell script for a college project where we use rsync and crontab to sync folders. I'm trying to offer to the user the possibility of customizing rsync and crontab parameters, as followed:
rsync accepts -auvn. I tried making the folling regex on my .sh file:
#!/bin/bash
#(...) lots of previous code
if [[ $1 =~ ^-a?u?v?n? ]]; then
if [ $1 != "-" ]; then
But it accepts arguments such as "-x". You can see that the second if shows that I have no idea of what I'm doing!
crontab accepts five parameters:
min, [0,59] or * if any;
hour, [0,23] or * if any;
day of week, [Mon, Tue, ... , Sun] or * if any;
month, [Jan, Feb, ... , Dec] or * if any;
year, 2017 and forward, or * if any;
I'm not worried with crontab regex (for now), but I'm struggling to make rsync regex work. I downloaded rsync source code to see how they treat their option parameters, but most scripts are written in C and it escapes the scope of this project. I could also just send whatever the user requests to rsync options and watch it explode, but I'm trying to give it a little treatment first.
Thank you!
[[ $1 =~ ^-[auvn]+$ ]]
I.e., check minus, then check any of "auvn" letters multiple times until the end. How to test in the command line:
$ [[ '-auvn' =~ ^-[auvn]+$ ]] && echo yes || echo no
yes
$ [[ '-a' =~ ^-[auvn]+$ ]] && echo yes || echo no
yes
$ [[ '-x' =~ ^-[auvn]+$ ]] && echo yes || echo no
no

How to check if a string contains some specific char inside an execute shell in Jenkins? [duplicate]

This question already has answers here:
Linux /bin/sh check if string contains X
(3 answers)
Closed 5 years ago.
I have the following strings: deploy_tag and version_number .
deploy_tag can be "2.8.6.1" or "origin/master" and version_number can only be numeric separated by dots like "1.1.2.3".
I want to do something like that:
if [[ $deploy_tag == *["\/"+]* ]]; then deploy_tag=$version_number; fi
Meaning: If $deploy_tag contains "/" then set it's value with the value of $version_number.
This whole shell script is part of a shell execution within a Jenkins job.
The problem is that seems like something is wrong with my regex but I can't find what... can you?
I checked some other questions on stackoverflow but I couldn't find the issue with my regex.
Edit #1:
Here's an example from Jenkins build log:
[social-portal] $ /bin/sh -xe /tmp/hudson1162745529550311655.sh
+ [[ origin/master =~ / ]]
/tmp/hudson1162745529550311655.sh: 2: /tmp/hudson1162745529550311655.sh: [[: not found
+ echo deploy: origin/master
deploy: origin/master
+ echo version: 2.7.4
version: 2.7.4
+ mkdir output
And that's the code which generates the problem (including debug echo's):
if [[ $DEPLOY_TAG =~ / ]]; then DEPLOY_TAG=$VERSION_NUMBER; fi
echo deploy: $DEPLOY_TAG
echo version: $VERSION_NUMBER
Jenkins is using /bin/sh, which you cannot assume is bash. Even if /bin/sh is a link to some version of bash, some bash features may not work properly. You need to use a POSIX-compatible construct.
case $deploy_tag in
*/* ) deploy_tag=$version_number ;;
esac

How to match the regex for the below pattern?

I am trying to write a script which should work out like this below but somehow am not able to get the write way to put the syntax.
I have folders like S_12_O_319_K4me1.
While the contents are S_12_O_319_K4me1_S12816.sorted.bam in each folder.
So I wanted to write a script where my my script goes into my folder of the same name in a loop and then identifies the *.bam file and perform the operation, but I am unable to put the regex. This is what I tried:
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3
S_12_O_319_K27ac"
for s in $samples; do
echo "Running SPP on $s ..."
Rscript $spp_run -c=$bam_loc/$s/${s}_S[[0-9]+\.sorted.bam -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
I am not being able to recognize the digits with the above regex match.
Where am I getting it wrong?
Edit:
I tried below still it does not work, problem with parsing in the Rscript, but why will this be a problem
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/tools/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3"
for s in $samples; do
echo "Running SPP on $s ..."
echo $bam_loc/$s/${s}_S*.sorted.bam
inbam=$bam_loc/$s/${s}_S*.sorted.bam
echo $inbam
Rscript $spp_run -c=$inbam -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
echo "done"
Error
Error in parse.arguments(args) :
ChIP File:/path/ChIP-Seq/output/S_12_O_319_K27me3/S_12_O_319_K27me3_S*.sorted.bam does not exist
Execution halted
Does not recognize the file even though $inbam value is /path/ChIP-Seq/output/S_12_O_319_K27me3/S_12_O_319_K27me3_S12815.sorted.bam
You can use a regex in a find command :
export spp_run=/path/phantompeakqualtools/run_spp.R
export bam_loc=/path/ChIP-Seq/output
export dir
samples=(S_12_O_319_K27me3 S_12_O_319_K4me1 S_12_O_319_K4me3 S_12_O_319_K27ac)
for dir in ${samples[#]}; do
find . -type f -regex ".*/*${dir}_S[0-9]+\.sorted\.bam" \
-exec bash -c 'echo Rscript $spp_run -c=$bam_loc/${dir}/${1##*/} -savp -out=$bam_loc/${dir}/${dir}".run_spp.out"' _ {} \;
done
Note : just remove the echo before the Rscript if the output meets your needs.
I found answer to my query and below is the code. Not an elegant one but it works. I realized that the Rscript requires full name and full path so I just initialized the output of the echo command to a variable and passed it to the Rscript as input file argument and it gets a full path with full filename so now it recognizes the input file.
Not an elegant way but still it works for me.
#!/bin/bash
#$ -S /bin/bash
spp_run=/path/tools/phantompeakqualtools/run_spp.R
bam_loc=/path/ChIP-Seq/output
samples="S_12_O_319_K27me3
S_12_O_319_K4me1
S_12_O_319_K4me3"
for s in $samples; do
echo "Running SPP on $s ..."
echo $bam_loc/$s/${s}_S*.sorted.bam
inbam=$bam_loc/$s/${s}_S*.sorted.bam
echo $inbam
infile=`echo $inbam`
Rscript $spp_run -c=$infile -savp -out=$bam_loc/$s/${s}".run_spp.out"
done
echo "done"
Thanks everyone for the suggestions and comments. My code is not elegant but it is working so I put the answer here.

bash regular expression format

My code have problem with compare var with regular expression.
The main problem is problem is here
if [[ “$alarm” =~ ^[0-2][0-9]\:[0-5][0-9]$ ]]
This "if" is never true i dont know why even if i pass to "$alarm" value like 13:00 or 08:19 its always false and write "invalid clock format".
When i try this ^[0-2][0-9]:[0-5][0-9]$ on site to test regular expressions its work for example i compered with 12:20.
I start my script whith command ./alarm 11:12
below is whole code
#!/bin/bash
masa="`date +%k:%M`"
mp3="$HOME/Desktop/alarm.mp3" #change this
echo "lol";
if [ $# != 1 ]; then
echo "please insert alarm time [24hours format]"
echo "example ./alarm 13:00 [will ring alarm at 1:00pm]"
exit;
fi
alarm=$1
echo "$alarm"
#fix me with better regex >_<
if [[ “$alarm” =~ ^[0-2][0-9]\:[0-5][0-9]$ ]]
then
echo "time now $masa"
echo "alarm set to $alarm"
echo "will play $mp3"
else
echo "invalid clock format"
exit;
fi
while [ $masa != $alarm ];do
masa="`date +%k:%M`" #update time
sleep 1 #dont overload the cpu cycle
done
echo $masa
if [ $masa = $alarm ];then
echo ringggggggg
play $mp3 > /dev/null 2> /dev/null &
fi
exit
I can see a couple of issues with your test.
Firstly, it looks like you may be using the wrong kind of double quotes around your variable (“ ”, rather than "). These "fancy quotes" are being concatenated with your variable, which I assume is what causes your pattern to fail to match. You could change them but within bash's extended tests (i.e. [[ instead of [), there's no need to quote your variables anyway, so I would suggest removing them entirely.
Secondly, your regular expression allows some invalid dates at the moment. I would suggest using something like this:
re='^([01][0-9]|2[0-3]):[0-5][0-9]$'
if [[ $alarm =~ $re ]]
I have deliberately chosen to use a separate variable to store the pattern, as this is the most widely compatible way of working with bash regexes.

How to find and replace special chars within a string in zsh

I'm trying to build a secure copy protocol quick function. When I run the command it will work with a single file OR with the entire directory, but as soon as I put a /* after the local_repo it returns zsh: no matches found: hackingedu/*.
If I put the command scp hackingedu\/\* hackingedu the command works properly. I think I'm on the right track, but can't get it to work.
contains() {
string="$1"
substring="$2"
if test "${string#*$substring}" != "$string"
then
# echo '$substring is in $string'
return 1 # $substring is in $string
else
# echo '$substring is not in $string'
return 0 # $substring is not in $string
fi
}
# Quickly scp files in Workspace to Remote
function scp() {
local_repo="$1"
remote_repo="$2"
# find all the `*` and replace with `/*`
if [ contains $local_repo '*' ]; then
# replace all instances of * with \* <- HOW TO DO
fi
command scp -r $LOCAL_REPOS/$local_repo $ALEX_SERVER_UNAME#$ALEX_SERVER_PORT:$ALEX_REMOTE_ROOT_PATH/$remote_repo
# Description: $1: Local Repo | $2: Remote Repo
# Define ex: scpp local/path/to/file/or/directory/* remote/path/to/file/or/directory/*
# Live ex: scpp alexcory/index.php alexcory/index.php
# Live ex: scpp alexcory/* alexcory/*
#
# This Saves you from having long commands that look like this:
# scp -r ~/Google\ Drive/server/Dev/git\ repositories/hackingedu/* alexander#alexander.com:/home2/alexander/public_html/hackingedu/beta
}
Command trying to execute: scp -r ~/Google\ Drive/server/Dev/git\ repositories/hackingedu/* alexander#alexander.com:/home2/alexander/public_html/hackingedu/beta
Any ideas on how to find and replace an *? If there's a better way to do this please do tell! :)
If you know how to do this in bash I would like your input as well!
References:
How do you tell if a string contains another string in Unix shell scripting?
ZSH Find command replacement
ZSH Find command replacement 2
Using wildcards in commands with zsh
You can either prefix your scp call using noglob (which will turn off globbing for that command, e.g. noglob ls *) or use
autoload -U url-quote-magic
zle -N self-insert url-quote-magic
zstyle -e :urlglobber url-other-schema '[[ $words[1] == scp ]] && reply=("*") || reply=(http https ftp)'
the above should make zsh auto quote * when you use scp.
[...]
BTW, in any case, you should learn that you can easily quote special characters using ${(q)variable_name}, e.g.
% foo='*&$%normal_chars'
% echo $foo
*&$%normal_chars
% echo ${(q)foo}
\*\&\$%normal_chars