bash rematch as chroot - bash

I'm using this in my script and it works fine on my root server and on some others I tested.
But there's a problem when using it on my webhosting (Hosted Plesk): The chrooted shell, it doesn't output anything. Just quits. My webhoster said I need to use the absolute paths, but I dont know how to apply this on the bash rematch.
#!/bin/bash
str='"<result="Abc1234" />"'
regex='<result="([0-9a-zA-Z._-/:]*)" />'
[[ $str =~ $regex ]] && echo ${BASH_REMATCH[1]}
(My first post here, sorry if I forgot something or misformatted this whole post)

In the discussion below the question it turned out that the issue is related to different default locales on the servers. Make sure that you are running the command with the right locale:
LANG=en_US.UTF-8 bash script.sh
(en_US.UTF-8) turned out to be the right locale in your case.
PS: Please also keep in mind what Ondrej K. says.

Instead of:
regex='<result="([0-9a-zA-Z._-/:]*)" />'
say:
regex='<result="([0-9a-zA-Z._/:-]*)" />'
- is moved to where it no longer can be considered meaning a range.
Actually I am a surprised it worked on the other system. I've replaced && echo ${BASH_REMATCH[1]} with ; echo $? (this was another possible debugging step) and was getting 2 which according to man bash means "syntactically incorrect regular expression".
If this doesn't help. Than we must be seeing different reason, way our shell interpret the script, but in any case printing the return status could then be the next step to take.

Related

Jenkins Execute shell if then statement fails with `Bad substitution`

I need an if statement in Jenkins Execute Shell, but it always fails on the same line, regardless of what’s there.
I’m trying to do something like this:
if [ " ${BuildVariants[*]} " =~ " VariantA " ]; then
# fails on this line even this line is just a comment
variant_config=""
fi
it fails when I try to assign a variable there, fails when I try to echo "anything", fails even on comment (as example above)
Reason: Bad substitution
Note: There's anything specified in Configure System, so it should be using default Bash.
What the problem might be?
I don't think =~ works inside of [ ... ] -- use [[ ... ]] instead.
Shellcheck is a great tool for find these types of things; it would show that you've hit SC2074.
re:
fails on this line even this line is just a comment
You cannot have an "empty" then block. You can use just : as code to be executed:
if [[ "$foo" == "bar" ]]; then
:
fi
Next idea: get your code to run in a shell script, then put the code up in Jenkins. You will probably need to mock up some of the Jenkins-supplied input to do that, but it takes one more moving part out of the equation. If the code runs from the command line and doesn't in Jenkins, then you need to start looking for Jenkins-specific causes, like maybe it's being run in a csh instead of Bash (I see you mention this specific possibility already, but maybe there's something else like it -- I don't know Jenkins, sorry).
So the problem was that I supposed Jenkins was giving me an array, but it was giving me a string. (I used with Extended Choice Parameter, with multiple choices).
So the condition should've been [[ "$BuildVariants" == *"VariantA"* ]].

Why is executing a ruby command on bash to command file not working?

Code from .command file:
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [$game_choice == $g1]
then
ruby Hi-Lo.rb
fi
Output:
Welcome to Ruby_Games! So far, you can play Hi-Lo.
What game would you like to play?
Hi-Lo
/Users/Abbas/Desktop/Ruby_Games/LAUNCHER.command: line 6: [Hi-Lo: command not found
logout
So what exactly is going wrong? Thanks
I believe you need double quotes in your if statement
Similar to example 6.4 here: http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-6.html
cd "$(dirname "$0")"
g1=Hi-Lo
echo Welcome to Ruby_Games! So far, you can play $g1.
echo What game would you like to play?
read game_choice
if [ "$game_choice" = "$g1" ]
then
ruby Hi-Lo.rb
fi
You need spaces between each element of the test (aka [) command. That is, you need a space between [ and $game_choice, between $game_choice and =, etc. Also, as #GregHNZ pointed out, you should use double-quotes around variable references, in case they contain spaces or certain other shell metacharacters. Finally, == in a test expression is a bash extension; use = instead, and it'll work in more basic shells as well. Result:
if [ "$game_choice" = "$g1" ]
Spaces are important delimiters in shell syntax; there are places they're required and places they're forbidden, and very very few places where they're optional. In many languages, you can add or remove spaces to make the code more readable, but that's not the case in shell.
BTW, I recommend using shellcheck.net; it does a pretty good job of spotting errors like this. Actually, it points out a couple I didn't think of: you should add a shebang line to the beginning of the script, and using cd without checking for an error risks the rest of the script running in an unexpected directory. So you should use something like this:
#!/bin/bash
cd "$(dirname "$0")" || {
echo "Error cd'ing to the script's directory" >&2
exit 1
}

Path variables become longer and longer after doing source ~/.bashrc

This might be a stupid question, but I wonder how to avoid this problem.
In my ~/.bashrc file, I add some local paths. The following is an example of the PYTHONPATH. In my work environment, I need to do "source ~/.bashrc" from time to time, and the following PYTHONPATH becomes longer and longer which is quite annoying.
Instead of appending to the existing PYTHONPATH, it might be nicer if I can append it to the "clean" PYTHONPATH. Is there anyway of doing this?
export PYTHONPATH=$PYTHONPATH:$CLIENTS:$EXPERIMENTAL/my_pythonlib:/mnt/src/cloud/chanwcom/chanwcom-speech/mnt/experimental/users/chanwcom/bin:$CK_MEDIA_FRAMEWORK
EDIT: I answered the question about keeping a clean PATH.
#mklement0 commented correctly, that the OP is talking about the PYTHONPATH.
I could correct my answer, but perhaps other readers have the same problem for PATH.
Dear Chanwcom, you can use the methods beneath, you only need to rename the variables.
Add some tests before expanding your path. Choose one of these examples.
if [[ -z "${my_clean_path}" ]]; then
my_clean_path="${PATH}"
fi
# some more commands
PATH="${my_clean_path}:${PYTHONPATH}"
or
if [[ -z "${python_added}" ]]; then
PATH="${PATH}:${PYTHONPATH}" # PATH += also possible here
fi
or (my favorite, without additional variables)
if [[ "${PATH}" != *${PYTHONPATH}* ]]; then
PATH="${PATH}:${PYTHONPATH}" # PATH += also possible here
fi
or open a second shell before changing the path. exit to the first shell and open a new fresh shell.
The "right" way to solve this is as chepner mentioned in a comment -- modify your PYTHONPATH in .bash_profile which gets run at login, rather than in .bashrc which gets run for every shell.
If you're unable to adjust the scripts or tools that append repeated items to your path, you may be able to clean things up by removing non-unique values.
Here's a strategy I use, which involves converting my $PATH to an array, inverting the array (i.e. turning array values into subscripts of an associative array) and then rebuilding the path from the array index:
if [[ ${BASH_VERSINFO[0]} -ge 4 ]]; then
path_a=( ${PATH//:/ } )
declare -A path_b=()
for i in ${path_a[#]}; do path_b[$i]=1; done
IFS=: eval 'PATH="${!path_b[*]}"'
fi
export PATH
You can adjust this for PYTHONPATH easily enough.
Note that associative arrays were introduced with Bash version 4, so they may not be available with the default bash in OSX. You should be fine just about anywhere else that's modern, though.
Note also that this solution will break if any of the directories in the path contain colons. But your path would be broken in that case anyway, I think.
Also, note that this solution uses eval, which some people consider dangerous, unclean, smelly. In the right setting, though, it can be a fine cheese.

Bash script giving me a different result on reboot?

I worked on a Bash script for the last day or so and running and debugging it directly on the shell.
The final script will be executed when the Ubuntu server gets rebooted.
I have started testing this, but my script gives me a different result then what I was expected.
I have narrowed it down to an "or condition" and rewrote a more simpler script to test this anomaly:
A call to this script has been made in /etc/rc.local, with a redirection of the output to a log file (log/reboot.log).
I have this in my script (as a test):
#!/bin/bash
YESTERDAY=20131103
SYS_DATE=20131104
LAST_START=20131104
if [[ $LAST_START = $YESTERDAY || $LAST_START = $SYS_DATE ]];
then
echo "is equal"
else
echo "is not equal"
fi
Executing in the shell I get "is equal" (the right answer). After the reboot in the log I get "is not equal".
Could someone tell me why?
I am guessing here,
But do you realize your /bin/sh is not your SHELL.
In UBUNTU and Debian, /bin/sh is DASH, your login shell is BASH.
So it might be related to your syntax of [[ ]] which is BASH.
Did you right in your top of the script:
#!/bin/sh
or
#!/bin/bash
[[
The [[ builtin is a bashism, and has somewhat better-defined semantics
than [ (a.k.a. test). However, it is still quite reasonable to use [
instead, and portable scripts must do so. Note that argument handling
is not quite the same; as above, use = rather than ==.
See here:
https://wiki.ubuntu.com/DashAsBinSh
the right way to do stuff here
The best solution would be actually to put your script in /etc/init.d and link it to run level 6. Which is the run level executed when rebooting. You should consider reading man 8 init when you have got some spare time. It will help you understand how your system is starting and shuting down.

Why can I execute a command in a terminal window just fine but encounter an error in a bash script?

I've been organizing my music library as of late, and I'm trying to make everything "look" the same. All my songs should look like 04 John Barleycorn.m4a, but some of them, coming from multi-disk sets, look like 2-04 John Barleycorn.m4a. So I immediately thought, "Why not make a bash script to do all of this tedious work for me?" Little did I know, I would spend more time trying to figure out this "bug" than it would take to just do it by hand. Only one small difference: I wouldn't learn anything doing it by hand!
So here's my script:
#!/bin/bash
filename="/tmp/fileout.txt"
find . -name '?-*.???' > $filename
cat $filename | while read line
do
echo ${line:1}
newname=$(echo ${line%\/*}/${line#*-})
echo $newname
#mv \"$line\" \"$newname\"
done
It should be simple enough, right? It finds all the files with the multi-disk format, and puts them in a text file. Each line is then read back, reformated, and is "moved" to its new location/file name. (some parts are commented out since I want to make sure things "looked" good before moving files) However, when I first tried it out (after things "looked" good and removed the # in front of mv), I kept getting
mv: target `Barleycorn.m4a"' is not a directory
and I think that's because the spaces are not being escaped. I thought by putting quotes around it would solve it, but apparently not.
But I'll try to fix that later. Here's my buggy issue. I want to remove the first character (a period) in the file name (just an example...I don't really need to do this for any reason):
line="./Traffic/Smiling Phases/04 John Barleycorn.m4a"
echo ${line:1}
works just fine by typing that in command-line.
But in a bash script, it responds with:
/home/kyleowen/filerenamer.sh: 15: Bad substitution
I've gotten this error many times before when using ${var//foo/bar/} and other string operations within curly braces.
Why is it doing this? Doesn't my script effectively run all operations as if they were in command-line?
I would love a working bash script, sure...but I'm mainly asking why I'm getting a Bad substitution error when working with string operations. Thanks!
EDIT: I found my quite embarrassing mistake...never did I mention how I was executing these scripts. I was executing them as sh test.sh instead of bash test.sh. I assumed sh would execute them as your user's default shell, but I guess I'm wrong (or the default shell is not bash).
Thanks for the tips on input redirection! I'll post back what I have when I get something that works.
There are a number of quoting inconsistencies:
while read line
do
echo "${line:1}"
newname="${line%\/*}/${line#*-}"
echo "$newname"
# mv "$line" "$newname"
done < <(find . -name '?-*.???')
In general advice: use input redirection instead of piping into read
Reason: the while loop woulld execute in a subshell due to the pipe
Try it without the backslashes in the mv command line?
mv "$line" "$newname"
The backslashes makes mv look for files with literal double quotes in the filename.

Resources