Wiggins has asked for the wisdom of the Perl Monks concerning the following question:

This is a puzzle of a cross-domain fashion in multiple environments.
Problem: an Perl installation script that installs a Perl program that auto-starts at boot, and can be started or stopped from the command line. In any release of RHEL, CentOS, Debian, Ubuntu, or Kali.

I have found a bash script that seems to reliably identify 'system5-init', 'upstart', and 'systemd' as foundations for process control. Running the script in back-ticks has interpretation problems. Using 'system' will only return the exit value, not the STDOUT (which is possibly usable, but rather opaque).

#create the bash script to determine whic Init System my $tmpScript = "/tmp/whichSysInit"; my $whichInit = <<"END"; #!/bin/bash if [[ `/sbin/init --version 2>/dev/null` =~ upstart ]]; then echo using upstart; elif [[ `systemctl` =~ -\.mount ]]; then echo using systemd; elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then echo using sysv-init; else echo cannot tell; fi END open OPT, "> $tmpScript"; print OPT $whichInit; close OPT; chmod 0555, $tmpScript; #run that script to get answer my $rslt= `$tmpScript`; #unlink $tmpScript; # cleanup print " Initialization is $rslt\n"; #react to the result #if ($rslt =~/using\s(?<si>\S+)/){ # my $sysInit= $+{si};
When I run the file left in /tmp/ from the command line, it echos the appropriate string.
When run the file in back-ticks the following errors are produced:
/tmp/whichSysInit: 2: /tmp/whichSysInit: [[: not found /tmp/whichSysInit: 1: /tmp/whichSysInit: systemctl: not found /tmp/whichSysInit: 4: /tmp/whichSysInit: [[: not found /tmp/whichSysInit: 6: /tmp/whichSysInit: [[: not found Can not determine System Init mechanism <>. Exiting
I searched for the program '[[', but none was found.
Linux ubuntu 3.11.0-26-generic #45~precise1-Ubuntu SMP Tue Jul 15 04:02:35 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

The shell in the environmant is '/bin/bash'
Maybe the '#!' on line 1 isn't run? And bash isn't what is interpreting the script?
Thoughts?

It is always better to have seen your target for yourself, rather than depend upon someone else's description.

Replies are listed 'Best First'.
Re: Back-ticks and bash
by haukex (Archbishop) on Oct 08, 2016 at 16:08 UTC

    Hi Wiggins,

    Maybe the '#!' on line 1 isn't run?

    That seems to be the case because the line doesn't begin with #!, it begins with the whitespace of the indentation. AFAIK Perl uses /bin/sh to execute backticks, and so it seems your shell script is run with /bin/sh instead of bash, and I guess sh doesn't have the [[ builtin. Remove the indentation and your code works for me.

    However, why use a bash script at all, when you could just do all the stuff your bash script is doing in Perl? If you want to capture external commands' STDOUT and STDERR, I'd suggest something like IPC::Run3 or Capture::Tiny.

    Hope this helps,
    -- Hauke D

      Yes, this is what it takes. The leading space breaks the rule. Thanks, it was right there in front of me!

      It is always better to have seen your target for yourself, rather than depend upon someone else's description.

Re: Back-ticks and bash
by shmem (Chancellor) on Oct 08, 2016 at 20:04 UTC
    And bash isn't what is interpreting the script?

    Yes. Init scripts are always interpreted by /bin/sh, even if the default $SHELL is /bin/bash.

    qwurx [shmem] ~> /bin/bash -c 'if [[ 1 -eq 1 ]]; then echo yup; fi' yup qwurx [shmem] ~> /bin/sh -c 'if [[ 1 -eq 1 ]]; then echo yup; fi' /bin/sh: 1: [[: not found

    update: not sure what might befall within the systemd usurpation... *sigh*

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Back-ticks and bash
by hippo (Archbishop) on Oct 08, 2016 at 16:10 UTC

    Hmmm. Is it not the case that the leading whitespace prevents the shebang from being recognised? At that point it will be run by whatever the O/S chooses, which is probably not bash.

    I'm not entirely sure that I see the point of making the tests in a bash script anyway. Why not perform the tests directly inside your perl script? Surely that would be less hassle.

Re: Back-ticks and bash
by kcott (Archbishop) on Oct 09, 2016 at 06:14 UTC

    G'day Wiggins,

    "I searched for the program '[[', but none was found."

    It's part of the shell syntax (see the bash manpage). It's used in conjunction with ']]'. Both are reserved words. Searching in the manpage finds, among others:

    RESERVED WORDS ... The following words are recognized as reserved ... [[ + ]]

    and, later

    SHELL GRAMMAR ... [[ expression ]] ... the evaluation of the conditional expression expr +ession. ... ...

    — Ken

      What I remenbered was /usr/bin/[ which is an external program used for doing tests I believe, and that is still there. I always find bash syntax confusing and obscure.

      It is always better to have seen your target for yourself, rather than depend upon someone else's description.

        [ in bash is a synomym for test but it's not still a builtin. For backward compatibility, it behaves similarly to /usr/bin/[ , which means variables among its arguments are still expanded by the shell, which is not true for [[ . In other words, you have to write things like
        if [ "$x" = abc ]

        i.e. you need to quote the variables, while with `[[` you don't have to, as the shell processes the parameters before expansion:

        if [[ $x = abc ]]

        Also, `[[` introduces pattern matching [[ $x = ab* ]] and `=~` you might now from Perl.

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,