Re: Bash / Escaping quotes is driving me crazy . .

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Cameron,


Date: Tue, 23 Feb 2016 08:39:07 +1100
From: Cameron Simpson <cs@xxxxxxxxxx>
To: phil@xxxxxxxxxxxxx,	Community support for Fedora users
	<users@xxxxxxxxxxxxxxxxxxxxxxx>
Subject: Re: Bash / Escaping quotes is driving me crazy . .
Message-ID: <20160222213907.GA79479@xxxxxxxxxxxxxxx>
Content-Type: text/plain; charset=us-ascii; format=flowed

On 21Feb2016 14:18, Philip Rhoades <phil@xxxxxxxxxxxxx> wrote:
Date: Sat, 20 Feb 2016 16:40:01 -0800
From: Gordon Messmer <gordon.messmer@xxxxxxxxx>
[...]
On 02/20/2016 04:05 PM, Philip Rhoades wrote:
. . but why is there only a problem with the "flac" OR? - all three
files have at least one space in the filename:

Your mistake seems to be believing that the shell can understand the
way
you're nesting quotes.  It can't.  Each unescaped quote you're using
simply terminates the quoted string that preceded it. So your example:

  ssh localhost "find
/home/phil/music/ambient/RobertGass+OnWingsOfSong/OmNamahaShivaya
-maxdepth 1 -type f \\( -name "*.mp3" -o -name "*.m4a" -o -name
"*.flac"
\\)"

Because quoting shell commands to dispatch over ssh is tedious, I have this
script:

  https://bitbucket.org/cameron_simpson/css/src/tip/bin/sshx

which accepts an unquoted command line and does the work for you, so your
request would be written:

  sshx localhost find /your/music/dir -maxdepth 1 -type f \( -name
\*.mp3 -o -name \*.m4a -o -name \*.flac

i.e. exactly as you would without the leading "ssh localhost" to an shell
prompt.

Please feel free to fetch it (use the "Raw" link at top right) and use it. It
saves a lot of pain.


Excellent!  Thanks for that!


BTW, why "localhost"? Or is this just an example for test, to be used on other
hosts later when working?


Exactly.


OK, that all makes sense but there is a further issue - I was trying to keep
it simple - this whole line is inside a Ruby "system" command ie:

 system( "ssh .. " )

- so my working version is the same as your first option (without the
escaped '*'s) but with an extra '\' at each place.  I can't use the
second option because I need to use double quotes so that I can use
Ruby variables inside the double quotes eg:

 #{path}

All this means is that you need to take your shell command line, once you have a working one, and quote it again to express it correctly as a Ruby string.
Bear with me, because I don't yet speak Ruby.

SO first get your shell command line. Make it as simple as feasible. If you've
fetched my "sshx" script, that can be:

  sshx localhost find ...

quoted no more than any local "find" command would be. Now express that as a
Ruby string:

https://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Literals#Strings

Since you're using double quotes to allow # interpolation (this is not a great practive for command lines, to which we'll come later) you probably want to either run with a command line with no double quotes in it and with all the
backslashes doubled:

  shcmd = "sshx localhost find /dir -name \\*.mp3 ..."

If _are_ using a command line with double quotes, they can also be escaped, eg:

  shcmd = "sshx localhost find /dir -name \"*.mp3\" ..."

I'm imagining that you're expecting to replace "localhost" or the directory
with something like #{remotehost} and #{path} later, thus:

  shcmd = "sshx #{remotehost} find #{path} -name \"*.mp3\" ..."

and here we come to the issue of quoting yet again. Supposing your path has spaces or other shell punctuation in it. You also need to quote it, _before_
using it in your command line string.

I find it useful to have a "shell quote" function in my kit, whatever the
language. You can take any string to be used in the shell undamaged and
suitable quote it by replacing all single quotes with:

  '\''

and enclosing the whole result in a pair of single quotes. You would need to do
this for the variable you want to interpolate:

  qpath = shqstr(path)
  qremotehost = shqstr(remotehost)

and then interpolate _those_ values:

  shcmd = "sshx #{qremotehost} find #{qpath} -name \"*.mp3\" ..."

and finally running:

  system(shcmd)

However, it is better to avoid going through the shell at all if it is only an intermediary to running a single command (your single "ssh" command). Using system() with a carefully quoted string has all the same fiddliness as passing carefully constructed SQL to a database query: any tiny flaw in the quoting can lead to incorrect behaviour, and if any of the strings come from user input, that is also an avenue for attack (there are known as injection attacks, where use input is injected into a command you issue, perverting your intent):

  http://bobby-tables.com/

The URL above uses SQL because it is an incredibly command misuse, but htis issue applies equally well to shell commands constructed the way you are
constructing them.

To avoid going though the shell at all you want to invoke your command with the
Subprocess Ruby module:

  http://www.rubydoc.info/github/stripe/subprocess/Subprocess

Construct your command as a list of strings:

  cmd = ['sshx', remotehost, 'find', path, '-name', '*.mp3', ...]

and invoke Subprocess.popen to collect the resulting output. Notice that there's no quoting there at all, including of things like *.mp3. This is because the shell will never see these strings, and therefore you need only
present them directly as valid Ruby strings.


Wow! Thanks for taking the time to answer in such useful detail! I will have a look at all that - interesting stuff!

And thanks to everyone else who helped as well.

Regards,

Phil.
--
Philip Rhoades

PO Box 896
Cowra  NSW  2794
Australia
E-mail:  phil@xxxxxxxxxxxxx
--
users mailing list
users@xxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe or change subscription options:
https://admin.fedoraproject.org/mailman/listinfo/users
Fedora Code of Conduct: http://fedoraproject.org/code-of-conduct
Guidelines: http://fedoraproject.org/wiki/Mailing_list_guidelines
Have a question? Ask away: http://ask.fedoraproject.org



[Index of Archives]     [Older Fedora Users]     [Fedora Announce]     [Fedora Package Announce]     [EPEL Announce]     [EPEL Devel]     [Fedora Magazine]     [Fedora Summer Coding]     [Fedora Laptop]     [Fedora Cloud]     [Fedora Advisory Board]     [Fedora Education]     [Fedora Security]     [Fedora Scitech]     [Fedora Robotics]     [Fedora Infrastructure]     [Fedora Websites]     [Anaconda Devel]     [Fedora Devel Java]     [Fedora Desktop]     [Fedora Fonts]     [Fedora Marketing]     [Fedora Management Tools]     [Fedora Mentors]     [Fedora Package Review]     [Fedora R Devel]     [Fedora PHP Devel]     [Kickstart]     [Fedora Music]     [Fedora Packaging]     [Fedora SELinux]     [Fedora Legal]     [Fedora Kernel]     [Fedora OCaml]     [Coolkey]     [Virtualization Tools]     [ET Management Tools]     [Yum Users]     [Yosemite News]     [Gnome Users]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [Fedora Sparc]     [Libvirt Users]     [Fedora ARM]

  Powered by Linux