You are not logged in.

#1 2008-06-05 15:54:47

peets
Member
From: Montreal
Registered: 2007-01-11
Posts: 936
Website

Escaping shell metacharacters

I like using programs that others have already written. I like automating things. Hence I often need to call programs from within other programs, and this often means going through some sort of subshell. I don't know how to safely construct the string that the shell is supposed to execute.

Suppose I need to call something of the form

program arg1 arg2

Any of "program", "arg1" and "arg2" may contain shell metacharacters. I need to know 1. which character(s) the shell uses to separate the tokens, so as to "escape" those characters if they occur in "program", "arg1" or "arg2", and 2. which other characters the shell gives special meaning to, so as to escape them too.

Is there a way to query a shell for metacharacters and token separators? I'd like to write things that work no matter which shell they are run in. Or is there some sort of zealously maintained library that keeps track of various shells and their caprices? I like to write my scripts in perl.

Offline

#2 2008-06-06 08:25:22

gnud
Member
Registered: 2005-11-27
Posts: 182

Re: Escaping shell metacharacters

I think you are looking for the "qx" function in perl  (quote-execute). Read about it here http://perldoc.perl.org/perlop.html#Quo … -Operators

Offline

#3 2008-06-06 08:27:33

gnud
Member
Registered: 2005-11-27
Posts: 182

Re: Escaping shell metacharacters

Btw, both C and perl (and probably most others) use /bin/sh when they invoke shell commands. So there is no need to think about different shells, just use standard sh syntax. At least I think this is how it works smile

Offline

#4 2008-06-06 21:09:50

peets
Member
From: Montreal
Registered: 2007-01-11
Posts: 936
Website

Re: Escaping shell metacharacters

Thanks, the "perlop" page gave me a link to "perlsec" which gave me a link to "exec" which gave me a link to "system" which is what I want to use.

$res = system($program, $arg1, $arg2);

Basically "system" forks and calls execvp(3), which is a frontend to execve(2) except it expands its first argument according to $PATH. execve(2) executes a program with the given arguments. No shell is involved, so I don't need to escape anything!

It was pretty useless to be worried for such a trivial script (see below), but this issue popped up a lot whenever I was writing something. I'll know what to do now!

#!/usr/bin/env perl

my $music_library = "/all/mus";

use strict;
use File::Path;

for my $zip (@ARGV) {
    if($zip =~ /([^-]+) - (.+) -- Jamendo/) {
        my($artist, $album) = ($1, $2);
        $artist =~ s/\//\\\//g;
        $album =~ s/\//\\\//g;
        my $path = "$music_library/$artist/$album";
        mkpath $path;
        if(system('7z', 'x', "$zip", "-o$path") == 0) {
            unlink $zip;
        } else {
            warn "error while handling '$zip': $!"
        }
    } else {
        warn "not smart enough to process this file: '$zip'."
    }
}

Thanks again!

Last edited by peets (2008-06-06 21:10:15)

Offline

Board footer

Powered by FluxBB