bashshellperltcsh

forcing brace expansion in backticks or why is this inconsistent?


When using backticks (in perl) i seem to have some sort of inconsistency with brace expansion

print `ls -d ~/{a,b}`;

Works fine, but when i try

print `ls -d ~/{a}`;

I get:

ls: cannot access /home/user/{a}: No such file or directory

I have tried all sort of quoting, spacing and escapes but to no avail. my question is, is there a way to force the expansion? I realize I can avoid the issue all together if I just glob the stuff myself, but I'm curious about this behavior

i tried this under both bash and tcsh. when used directly under tcsh, the command works, but under bash it doesn't


Solution

  • Now, after your several edits, I understand that you may be using two different shells. And, also, that the one calling the shell is perl, not you.

    So, to cover the three elements:

    bash

    In bash. A simple {a} will not be expanded:

    $ echo ~/{a,b}
    /home/user/a /home/user/b
    
    $ echo ~/{a}
    /home/user/{a}
    

    Which is searched as a file by ls, and not found.

    The relevant part of the manual man bash is (emphasis mine):

    A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression.

    A {a} is lacking a required comma.

    The only alternative is to actually use

    $ print `ls -d ~/a`
    

    tcsh

    In tcsh: A simple {a} will be expanded (as in a csh shell):
    Using > as shell indicator for tcsh prompt:

    > echo --{a,b}++
     --a++ --b++
    
    > echo --{a}++
    --a++
    

    As a simple {} also will:

    $ echo --{}++
     --++
    

    The only braces that will not be removed will be {} and { and }.
    IIF (if and only if) they are recognized as "words". Most commonly surrounded by spaces:

    $ echo --{}++ == {} .. { :: } aa { bb
    --++ == {} .. { :: } aa { bb
    

    If a { or a } appear as part of a word, without the matching brace, is an error:

    > echo aa{bb
    Missing '}'.
    

    The only description of this on the man tcsh is really short (unclear?):

    > As a special case the words `{', `}' and `{}' are passed undisturbed.
    

    perl

    If the shell commands are called from perl, in the cases that do call a shell, like under Unix systems, the shell called is /bin/sh.

    An an additional twist, the /bin/sh is served by bash in most linux systems, by tcsh in FreeBSD and by ksh or csh in OpenBSD.

    It becomes difficult to predict the output of a perl called /bin/sh.

    You could make sure that an specific shell is called:

    #!/usr/bin/perl
    print `/bin/tcsh -c 'ls -d ~/{a,b}'`;
    

    Now the question remains: