How to accommodate spaces in a variable in a bash shell script? - bash

Hopefully this should be a simple one... Here is my test.sh file:
#!/bin/bash
patch_file="/home/my dir/vtk.patch"
cmd="svn up \"$patch_file\""
$cmd
Note the space in "my dir". When I execute it,
$ ./test.sh
Skipped '"/home/my'
Skipped 'dir/vtk.patch"'
I have no idea how to accommodate the space in the variable and still execute the command. But executing this the following on the bash shell works without problem.
$ svn up "/home/my dir/vtk.patch" #WORKS!!!
Any suggestions will be greatly appreciated! I am using the bash from cygwin on windows.

Use eval $cmd, instead of plain $cmd

Did you try escaping the space?
As a rule UNIX shells don't like non-standard characters in file names or folder names. The normal way of handling this is to escape the offending character. Try:
patch_file="/home/my\ dir/vtk.patch"
Note the backslash.

Related

Bash script: any way to collect remainder of command line as a string, including quote characters?

The following simplified version of a script I'll call logit obviously just appends everything but $1 in a text file, so I can keep track of time like this:
$ logit Started work on default theme
But bash expansion gets confused by quotes of any kind. What I'd like is to do things like
$ logit Don't forget a dark mode
But when that happens of course shell expansion rules cause a burp:
quote>
I know this works:
# Yeah yeah I can enclose it in quotes but I'd prefer not to
$ logit "Don't forget a dark mode"
Is there any way to somehow collect the remainder of the command line before bash gets to it, without having to use quotes around my command line?
Here's a minimal working version of the script.
#!/bin/bash
log_file=~/log.txt
now=$(date +"%T %r")
echo "${now} ${#:1}" >> $log_file
Is there any way to somehow collect the remainder of the command line before bash gets to it, without having to use quotes around my command line?
No. There is no "before bash gets into it" time. Bash reads the input you are typing, Bash parses the input you are typing, there is nothing in between or "before". There is only Bash.
You can: use a different shell or write your own. Note that quotes parsing like in shell is very common, you may consider that it could be better for you to understand and get used to it.
you can use a backslash "\" before the single quote
$ logit Don\'t forget a dark mode

sed with regular expression as a bash variable

We have an application that keeps some info in an encrypted file. To edit the file we have to put the text editor name in an environment variable in bash, for example, EDITOR=vi. Then we run the application and it opens the decrypted file in vi. I am trying to come up with a bash script that updates the encrypted file. The only solution that I can think of is passing sed command instead of vi to the EDITOR variable. It works perfectly for something like EDITOR='sed -i s#aaaa#bbbb#'.
Problem starts when I need space and regular expression. For example: EDITOR='sed -i -r "s#^(\s*masterkey: )(.*)#\1xxxxx#"' which return error. I tried running the EDITOR in bash with $EDITOR test.txt and I can see the problem. It doesn't like double quotes and space between them so I added a backslash before the double quotes and \s instead of space. Now it says unterminated address regex. For several hours I googled and couldn't find any solution. I tried replacing single quotes with double quotes and vice versa and everything that I could find on the internet but no luck.
How can I escape and which characters should I escape here?
Update:
Maybe if I explain the whole situation somebody could suggest an alternative solution. There is an application written by Ruby and it is inside a container. Ruby application has a secret_key_base for production and we supposed to change the key with EDITOR=vi rails credentials:edit --environment=production. I don't know Ruby and google did not return any ruby solution for automation so I could only think about sending sed instead of vi to Ruby.
How can I escape and which characters should I escape here?
That is not possible. Word splitting on the result of expansion cannot be escaped from inside the result of that expansion, it will always run. Note that filename expansion is also running over the result of the expansion.
Create an executable file with the script content and set EDITOR to it.
You could export a bash shell function, after some tries I got to:
myeditor() {
sed -i -E 's#^(\s*masterkey: )(.*)#\1xxxxx#' "$#"
}
export -f myeditor
EDITOR='bash -c "$#" _ myeditor'

Difficulty executing shell script with directory reference

I have a simple script
...
dir=`pwd`
echo $dir
cd ./selenium-grid-1.0.8/
CMD="ant -Dport=$1 -Dhost=$2 -DhubURL=http://172.16.1.137:4444 -Denvironment="$3"-DseleniumArgs="-firefoxProfileTemplate C:/software/rc_user_ffprofile -multiWindow" launch-remote-control"
echo $CMD
$CMD 2>&1
#End
Whenever i run this command, i get: ./register_rc.sh: line 16: C:/software/rc_user_ffprofile: is a directory
this directory has to be an argument to the -firefoxProfileTemplate option. How do i include that in this string without it baffing??
help
thnx
I believe your command should read:
CMD="ant -Dport=$1 -Dhost=$2 -DhubURL=http://172.16.1.137:4444 -Denvironment=\"$3\"-DseleniumArgs=\"-firefoxProfileTemplate C:/software/rc_user_ffprofile -multiWindow\" launch-remote-control"
The backslashes are used to "escape" the quotation marks.
The answers here telling to escape your quotes are wrong. That will pass those quotes directly to ant, I doubt that's what you want.
What's the reason to store the command in a variable? It's a very bad idea. Why can't you just write that command as is? If you want to achieve modularity or code reuse, then define a function.
If you want to display executed commands, use set -x.
Looks like you're mixing your quotes up. Take a look at the syntax highlighting that StackOverflow did for you.
I recommend generating the CMD variable in multiple steps, and make sure you \-escape your quotes.

How to format a Windows path to a Unix path on Cygwin command line

When using Cygwin, I frequently copy a Windows path and manually edit all of the slashes to Unix format. For example, if I am using Cygwin and need to change directory I enter:
cd C:\windows\path
then edit this to
cd C:/windows/path
(Typically, the path is much longer than that). Is there a way to use sed, or something else to do this automatically? For example, I tried:
echo C:\windows\path|sed 's|\\|g'
but got the following error
sed: -e expression #1, char 7: unterminated `s' command
My goal is to reduce the typing, so maybe I could write a program which I could call. Ideally I would type:
conversionScript cd C:/windows/path
and this would be equivalent to typing:
cd C:\windows\path
Thanks all. Apparently all I need are single quotes around the path:
cd 'C:\windows\path'
and Cygwin will convert it. Cygpath would work too, but it also needs the single quotes to prevent the shell from eating the backslash characters.
Read about the cygpath command.
somecommand `cygpath -u WIN_PATH`
e.g.
cmd.exe doesn't like single quotes. You should use double quotes
C:\test>echo C:\windows\path|sed "s|\\|/|g"
C:/windows/path
You replace back-slash by slash using unix sed
Below I use star "*" to seperate fields in s directive
sed "s*\\\*/*g"
The trick is to use one back-slash more than you might think needed
to answer your question to achieve
cd C:\windows\path
since you are in bash this just works as you want - but add single quotes
cd 'C:\windows\path'
As noted by #bmargulies and #Jennette - cygpath is your friend - it would be worth it to read the cygwin man page
man cygpath

command substitution but without breaking output into multiple arguments

Is there a way to do command substitution in BASH shell without breaking output into multiple arguments?
I copy the path of some directory (from the location bar in a GUI file browser) to clipboard and then issue the following command, where the command xsel returns the clipboard content, which is the path of the directory in this case:
cd `xsel`
But some path contain spaces or may even contain some special characters used by BASH.
How can I pass the output of a command as a single argument and without BASH messing with special characters?
cd "$(xsel)"
seems to handle all special characters (including $ and spaces).
My test string was boo*;cd.*($\: $_
$ mkdir "$(xsel)"
$ ls
boo*;cd.*($\: $_
$ file boo\*\;cd.\*\(\$\\\:\ \$_/
boo*;cd.*($\: $_/: directory
$ cd "$(xsel)"
$ pwd
/tmp/boo*;cd.*($\: $_
Have you tried:
cd "`xsel`"
That should do the job, unless you have dollars($) or back-slashes (\) in your path.
If you aren't doing this programmatically, most terminals in Linux let you paste from the clipboard with a middle-click on your mouse. Of course, you'll still need to put quotes before and after your paste, like #dave suggests.

Resources