http://www.perlmonks.org?node_id=849619

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

I am trying to use a perl one liner as
my $stat = $ssh->exec("perl -e /.firstboot | echo $?");
and what i want is to have $stat = 0 , if the file does not exist, and 1 f it does but i am getting an error: Search pattern not terminated at -e line 1. Need some help please Thanks, -Kamal. here is the whole script:
#!/usr/bin/perl use Net::SSH::Expect; use YAML; use Data::Dumper; use warnings; use strict; use diagnostics; ##################### # process the input ##################### my $in = YAML::LoadFile('test_input.yml'); my $version = $in->{test_instance}{version}; my $build = $in->{test_instance}{build}; my $host_data = $in->{host}[0]; my $modelnum = $host_data->{model_number}; my $company = $host_data->{company}; my $address = $host_data->{address}; #print Dumper($address), "\n"; my $ssh = Net::SSH::Expect->new( ssh_option => "-v -v -v", #ssh_option => "-v", #host => $address, host => "baseline-dc1", #host => "upgrade-dc1", #host => "upgrade-3d1", #host => "baseline-3d1", #host => "batterup-dc2", user => 'admin', #password => 'password', raw_pty => 1, #timeout => 2, log_stdout => 1, ssh_option => '-o StrictHostKeyChecking=no ' . '-o UserKnownHostsFile=/dev/null ' . '-o LogLevel=ERROR' ); $ssh->run_ssh(); $ssh->exec("stty raw -echo"); #my $ls = $ssh->exec("ls -l /"); # print($ls); # my $who = $ssh->exec("who"); # print ($who); $ssh->send("sudo -i"); $ssh->waitfor('Password:', 3); $ssh->send("Sourcefire"); print "logged in?\n"; my $catschedular = $ssh->exec("cat /sys/block/sda/queue/scheduler" +); my $echoconf = $ssh->exec("echo '/usr/lib/bigloo/3.1a' >> /etc/ld. +so.conf"); my $catconf = $ssh->exec("cat /etc/ld.so.conf"); my $ldconfig = $ssh->exec("ldconfig"); print "the part we care about:\n\n\n"; my $stat = $ssh->exec("if [ -e /.firstboot ]; then echo 1; else echo 0 +; fi"); #my $stat = $ssh->exec("[ -f /.firstboot ] && echo "1" || echo "0""); open OUT, "> /tmp/STAT.out"; print OUT $stat; close OUT; print "stat:|".$stat."|"; chomp $stat; my $newstat; $newstat = substr($stat, 0, 1); $stat = $newstat; print "new stat: |" . $newstat . "|\n"; print "old stat: |" . $stat . "|\n"; # testport returns 0 if the port accepts tcp connections my $https=system("testport $address 443"); print "before..."."|".$https."|"; chomp $https; print "after..."."|".$https."|";
The problem, is that /tmp/STAT.out contains the "prompt" in addition to "0" and i just want "0" which is the value of $stat

Replies are listed 'Best First'.
Re: One liner to test existance of a file
by Corion (Patriarch) on Jul 14, 2010 at 20:11 UTC

    Your code is not valid Perl code. Your snippet does not even run in your shell. See perlrun.

    Also, double quotes will be interpolated by Perl first. So your shell snippet won't look like you want. Do the following to see what goes wrong:

    my $snippet = "perl -e /.firstboot | echo $?"; print "Running <$snippet>\n"; my $stat = $ssh->exec("perl -e /.firstboot | echo $?");

    Also, why do you want to launch Perl on the remote end, when the unix shells have test to test for the existence of a file?

    Also see Filesys::Virtual::SSH

      This part of the code is inside an infinite loop to test if the remote linux host has booted or not. I am using Net::SSH::Expect hence you see $ssh->exec(); i am retrofitting this into an existing system. which has stopped working. so there are things like running a command on the remote system to populate $stat that i have to live with. I will try your suggestions, Thank you so much. I really appreciate it.
Re: One liner to test existance of a file
by ikegami (Patriarch) on Jul 14, 2010 at 23:19 UTC
    "perl -e /.firstboot | echo $?"

    has a number of problems.

    • $? is interpolated before ssh and thus the shell will ever see it.
    • Perl doesn't accept a program on the command line unless you use its -e option.
    • String literals generally need to be quoted in Perl.
    • You never tell Perl to exit with an error, so $? will never be set properly.

    The above should be

    q{perl -e'exit(-e "/.firstboot" ?1:0)' | echo $?}

    which can be simplified to

    q{perl -e'print -e "/.firstboot" ?1:0'}

    But why not just use the shell?

    q{test ! -e /.firstboot ; echo $?} -or- q{if [ -e /.firstboot ] ; then echo 1 ; else echo 0 ; fi}

    Also, you didn't specify what should be returned when it cannot be determined whether the file exists or not.

      if i use
      q{if [ -e /.firstboot ] ; then echo 1 ; else echo 0 ; fi}
      i get:

      0 root@baseline-dc1:~#

      The required output should be: 0 with NO new line, or carriage return, or space. somehow (i think) due to Net::SSH::Expect the prompt of the remote system is being appended to $stat hence i need to remove it
        That command does not output that at all. -n prevents echo from outputting a newline. As for the prompt, it comes from the shell. Don't run a shell interactively, hide its prompt, waitfor it, or exec a shell to execute the command, causing the connection to drop after the output has been obtained.
Re: One liner to test existance of a file
by aquarium (Curate) on Jul 15, 2010 at 04:51 UTC
    This is a bit clumsy and not very system/maintenance friendly way of getting remote system uptime, in my opinion.
    I think much better to poll via SNMP for the hrSystemUptime OID. This is reported in centiseconds for M$ systems and milliseconds for other (unix/linux/etc) systems. The relevant OID to read is .1.3.6.1.2.1.25.1.1.0
    Then you would end up with a much cleaner implementation using SNMP perl module instead.
    the hardest line to type correctly is: stty erase ^H