Notices


Reply
Thread Tools
Posts: 2,225 | Thanked: 3,822 times | Joined on Jun 2010 @ Florida
#1
I wrote a really, really tiny C commandline program that takes all arguments given to it, and prints them almost verbatim, just 'escaped' in the Bourne/POSIX shell sense of the word.

It's so simple, and not needed too often, so I almost feel like it doesn't need an announcement. But, I have found such a tool useful in some complex shell scripts (and in one case, it was downright necessary), so I wanted to go ahead and throw it up in the repos so others don't have to reinvent the wheel. (Plus it bugs me that there's no standard shell command with an easy to remember and type name to do this. Deep down I hope this might take off and spread.)

It's currently packaged for Maemo 5 [Edit1]and Maemo 4. For Maemo 5, it is[/Edit1] in extras-testing, please review/test, then vote here.

Latest C source code, as well as an alternative shell-script implementation dependant on sed (way less performant/efficient but equally functional, but it may be useful to some, and that's how I originally implemented it): on my github.

If asked, I will happily package it for other systems, I just did Maemo 5 for now since that's what I use [Edit1]also packaged up for Chinook/Diablo Maemo 4 as well now[/Edit1]. The source is so simple it should build virtually anywhere where a C compiler works.

[Edit1]P.S. Yes, there's a typo in the deb package "Description" field (last sentence, s/undesided/undesired/ ), but I felt like that wasn't significant enough to bother packaging it again. Still, if people feel I should package it just to fix that typo, I am amicable to doing so.
No one was voting on it so I figured I might as well remake the package with the typo fixed.
[/Edit1]
__________________
If you want to donate in support of anything that I do, you can do so with either of these options:
PayPal | Bitcoin: 1J4XG2z97iFEKNZXThHdFHq6AeyWEHs8BJ | [Will add other donation options eventually]

Last edited by Mentalist Traceur; 2015-02-14 at 23:15. Reason: Added Chinook+Diable to section choice; updated links.
 

The Following 9 Users Say Thank You to Mentalist Traceur For This Useful Post:
Posts: 2,225 | Thanked: 3,822 times | Joined on Jun 2010 @ Florida
#2
More technical explanation of the rationale:

Imagine that you have a shell script where you need to dynamically create a list of arbitrary strings. And you need to do this in several places in your code, so you wrap it up in a function.

The only way to 'return' a string from a shell function is to print it out and catch it with command substitution, or to set a variable that the caller then reads.

When you have multiple arbitrary strings (so any of them may have any arbitrary characters in them), if you just do that, you get just one variable containing the string, let's say $FOO. If you use $FOO (unquoted), word splitting may overzealously split some of your strings, or lose characters off the edges. If you use "$FOO" (quoted), then it's be treated as just one really big argument. If you do eval ... "$FOO", you're back to the equivalent of just using $FOO.

Some of the more featureful/bloated (depending on your viewpoint) shells support arrays - in which case you can make FOO an array, and you're set. But we can't rely on array support, since many shells don't have them. It's possible to do wierd voodoo to coopt the positional parameters ($1, $2, ...) as an array, and it's possible to use eval to kludge pseudo-arrays (where $N is some number, and you do eval ... \$FOO_$N ), but the code for that gets messy.

A relatively clean-looking solution is to wrap the strings up with something like esceval, and then make one big string out of the escaped strings. Now when you do eval ... "$FOO", it'll actually parse the "packed" strings into exactly the same separate strings as they were before the esceval.

Furthermore, even if you never have to pass them up to invoking functions, if you have to build the final set of arbitrary strings in a way where you don't have all the strings at once, and especially if you have an arbitrarily large number of strings that you need to 'get' before you can build the final set, esceval (or something like it) is way more legible than using one of the above-mentioned pseudo-array kludges.

It's this code clarity/simplicity, as well as functionality it enables for portable shell scripts, that made me like this approach enough to want to see it become commonly available. Now, obviously given the lack of such widespread-ness, for portability currently, you'd use the shell script variant I have up on github, since that just relies on printf and basic sed syntax, which are portable. But given how much more performant and simple a dedicated C program is, I look at the shell script variant as something that would be best phased out in favor of something more purpose-dedicated than invoking sed every time.
__________________
If you want to donate in support of anything that I do, you can do so with either of these options:
PayPal | Bitcoin: 1J4XG2z97iFEKNZXThHdFHq6AeyWEHs8BJ | [Will add other donation options eventually]
 

The Following 2 Users Say Thank You to Mentalist Traceur For This Useful Post:
Posts: 2,225 | Thanked: 3,822 times | Joined on Jun 2010 @ Florida
#3
Secondarily, there are shell scripting use cases where esceval (or something like it) is helpful and would make code more legible, even though it's not necessary.

Specifically where you have to pass complex strings (especially other shell commands) as arguments to some tool (e.g. if I want to run the find command, but I need to pass a not-trivial shell command to its '-exec' arguments, of I want to launch X-Term from a shell script and have it run some commands visible to the user in the console). May the shell script gods be merciful so that you never have to nest shell commands like that several levels deep.

In those cases, now that I have esceval, I would define a variable containing the legible, 'first-order' text of that to-be-nested shell command, then esceval it to encapsulate it in however many levels of shell escaping I need (e.g. FOO=[fancy shell script]; FOO=`esceval "$FOO"`; ... ), then substitute the final escaped result where it's needed.
__________________
If you want to donate in support of anything that I do, you can do so with either of these options:
PayPal | Bitcoin: 1J4XG2z97iFEKNZXThHdFHq6AeyWEHs8BJ | [Will add other donation options eventually]
 

The Following 2 Users Say Thank You to Mentalist Traceur For This Useful Post:
Posts: 2,225 | Thanked: 3,822 times | Joined on Jun 2010 @ Florida
#4
I went ahead and packaged a new version several days ago (the only change is that the "Description" field in the packaging is fixed), since no one was voting on the one in Testing anyway, so I wasn't going to lose any tester votes by doing so. Anyway, that was promoted to extras-testing for Fremantle several days ago now too. As before, testing+votes would be appreciated.

I also had the autobuilder build Chinook and Diablo versions. Not sure what happened with the Chinook build - it succeeded just like the others, but I don't see it among the list of versions on the package site.
__________________
If you want to donate in support of anything that I do, you can do so with either of these options:
PayPal | Bitcoin: 1J4XG2z97iFEKNZXThHdFHq6AeyWEHs8BJ | [Will add other donation options eventually]
 

The Following User Says Thank You to Mentalist Traceur For This Useful Post:
Reply

Tags
bourne, escape, esceval, posix, shell

Thread Tools

 
Forum Jump


All times are GMT. The time now is 04:17.