LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Bash '||' OR operator not working in Perl? (https://www.linuxquestions.org/questions/programming-9/bash-%7C%7C-or-operator-not-working-in-perl-4175650364/)

young_jedi 03-17-2019 04:30 PM

Bash '||' OR operator not working in Perl?
 
I'm trying to make a little Perl script to mount/umount devices on the command line.. I came up with the following
but in line 8 the '||' operator is not working (its works by itself on the command line)... BTW the scripts uses a while loop so I can keep toggling mount/umount devices.


Code:

while ( <<>> ) {
    system "clear";
    @devices=`lsblk -f | egrep -w 'mmcblk.|sd.' | awk '{print\$1" "\$3" "\$7}'`;
    foreach $index (0..$#devices) {
        print "$index: $devices[$index]";
    }
    $index = $_;
    system "udisksctl mount -b /dev/$devices[$index] > /dev/null 2>&1 || umount /dev/$devices[$index]";
    print "Enter an index number: ";
}


BW-userx 03-17-2019 05:13 PM

Quote:

Originally Posted by young_jedi (Post 5974827)
I'm trying to make a little Perl script to mount/umount devices on the command line.. I came up with the following
but in line 8 the '||' operator is not working (its works by itself on the command line)... BTW the scripts uses a while loop so I can keep toggling mount/umount devices.


Code:

while ( <<>> ) {
    system "clear";
    @devices=`lsblk -f | egrep -w 'mmcblk.|sd.' | awk '{print\$1" "\$3" "\$7}'`;
    foreach $index (0..$#devices) {
        print "$index: $devices[$index]";
    }
    $index = $_;
  system "udisksctl mount -b /dev/$devices[$index] > /dev/null 2>&1 || umount /dev/$devices[$index]";
    print "Enter an index number: ";
}


code only does what you tell it to.
I do not do perl
https://www.tutorialspoint.com/perl/...rs_example.htm
but, examine your logical condition

if true && true || false
if false || do something

the condition you're using needs to give back a status of completion or a fail of completion in order to execute any further code within that statement.

Code:

is true no echo
[[ -d /usr ]] || echo "yes"
is false because there is a /usr
it fires an echo
[[ ! -d /usr ]] || echo "no"

maybe something like this
Code:

[[$(system "udisksctl mount -b /dev/$devices[$index] > /dev/null 2>&1) ]] || umount /dev/$devices[$index]";
checks the return value within the brackets ( ) so it can act upon it.
therefore it should be written like this.
Code:

# if mounted then un-mount && , or if not mounted then mount ||
[[$(system "udisksctl mount -b /dev/$devices[$index] > /dev/null 2>&1) ]] &&
umount /dev/$devices[$index]" ||
mount /dev/$devices[$index]";

but written in perl script, not bash. Though I am not sure in perl if that is a true ternary operator in perl either.
this is better sutied for your perl script
The ternary operator in Perl

young_jedi 03-17-2019 08:08 PM

Thanks for replying, Perl is a glue programming language so it should execute bash code natively (I don't have to do what you're saying in a bash script). But I see what you're saying about surrounding it in brackets to capture the return status and having that factor in on whether the next command should run or not. Ill check to see how to do that in Perl and if that works, thank you..

scasey 03-17-2019 11:02 PM

The syntax for the system call is
Code:

system()
see this
Note that the default shell for the system() in Unix is sh -c -- not sure what the default is for Linux. Might be bash, but you'd need to check.

rnturn 03-19-2019 05:00 PM

Quote:

Originally Posted by young_jedi (Post 5974863)
Thanks for replying, Perl is a glue programming language so it should execute bash code natively (I don't have to do what you're saying in a bash script). But I see what you're saying about surrounding it in brackets to capture the return status and having that factor in on whether the next command should run or not. Ill check to see how to do that in Perl and if that works, thank you..

Check the "perlfunc" manpage for the "system()" call. I think what you're attempting to do in a single system() call may need to be split into two calls. The example on that page:
Code:

@args = ( "command", "arg1", "arg2", ... )
system( @args ) == 0
    || die "system @args failed: $?"

might be adapted to what you're trying to do:
Code:

$mount_cmd = "udisksctl mount -b /dev/$devices[$index] > /dev/null 2>&1";
$umount_cmd = "umount /dev/$devices[$index]";
system( $mount_cmd ) == 0
    || system( $umount_cmd );

Worth a try.

HTH...

Cheers.

young_jedi 03-19-2019 06:40 PM

@scasey, You can omit the parens as long as it doesnt change the meaning of the code.

@rnturn, Thats I good idea I'll try braking it up into variables, and if that doesnt work ill try two system calls thanks.. Im trying to write elegant code....

young_jedi 03-20-2019 08:39 PM

@rnturn thanks it works now though I cant get >/dev/null 2>&1 to work for the same reason... But besides that it all works perfectly..

Code:

This is free software..

#!/usr/bin/perl
$simulate_return='xdotool key Return ; xdotool key Return';
system $simulate_return;

while ( <> ) {
    system 'clear';

    @devices=`lsblk -f | egrep -w 'mmcblk.|sd.' | awk '{print\$1" "\$3" "\$7}'`;
    foreach $index (0..$#devices) {
        print "$index: $devices[$index]";
    }

    print "\n", 'Choose an index number: ';
    $selected = <>;
    system $simulate_return;
   
    $mount="udisksctl mount -b /dev/$devices[$selected]";
    $umount="udisksctl unmount -b /dev/$devices[$selected]";
    system( $mount ) == 0 || system( $umount );
}

I'm marking this thread as solved, but if anyone knows how I cant get the '>/dev/null 2>&1' part to work that will be great! I even tried using the long form, e.g.:
Code:

$mount="udisksctl mount -b /dev/$devices[$selected] >/dev/null 2>&1";
$umount="udisksctl unmount -b /dev/$devices[$selected]";
unless ( !system $mount ) {     
    system $umount;
}


NevemTeve 03-20-2019 10:09 PM

What is the 'short form'? What "doesn't work" actually means?

young_jedi 03-21-2019 11:13 PM

Quote:

Originally Posted by NevemTeve (Post 5976086)
What is the 'short form'? What "doesn't work" actually means?

This is the short-syntax:

Code:

$mount="udisksctl mount -b /dev/$devices[$selected] >/dev/null 2>&1";
$umount="udisksctl unmount -b /dev/$devices[$selected]";
system( $mount ) == 0 || system( $umount );

Basically im using bash's OR '||' operator to toggle between mount/umount.. If the device is already mounted
then it will unmount it, but in the process the mount command will return in error.. I want to "hide" that error
by redirecting STDERR to /dev/null.. But its not working.. If you notice in my working code above I removed
'>/dev/null 2>&1' cause it broke the script..

NevemTeve 03-22-2019 10:50 AM

Try this in shell:
Code:

true  >/dev/null 2>&1 || echo "true(1) gave error"
false >/dev/null 2>&1 || echo "false(1) gave error"

result:
Code:

false(1) gave error
Try this in perl:
Code:

#!/usr/bin/perl -w

use strict;

system ('false >/dev/null 2>&1') == 0 || system ('echo "false(1) gave error"');
system ('true  >/dev/null 2>&1') == 0 || system ('echo "true(1) gave error"');

result:
Code:

false(1) gave error
Note: there is a well known problem here: in shell 0=success, other=errorcode; in C/Perl/etc 0=false, 1=true.
(It would be less problematic, if false(1) would be called fail(1), and true(1) would be called success(1).)

young_jedi 03-23-2019 07:20 PM

So you're saying the nonzero return values are actually true (backwords from the traditional "0 but true" notion that the shell uses). If that's the case than all I should have to do is remove the negation (!) operator, but somehow I don't think that's going to work... Cause i'm pretty sure I tried that already, but i'll try it again.. But rather what if the bash command is giving a nonzero exit status that actually indicates success (as they can return whatever their programmed to), is that a possability? Anyway thanks for bringing that to my attention, I didn't know that until now.

bigearsbilly 03-25-2019 04:42 AM

well, for a kick-off you are doing the redirections in the wrong order:

Code:

>/dev/null  # stdout to null
2>&1        # stderr to stdout (i.e. null!)


bigearsbilly 03-25-2019 05:25 AM

you don't use awk etc from Perl,

take a look at what Perl can really do:
using the -J switch on lsblk
(You may find it interesting, or not)

Code:

use strict;
use Data::Dumper;
use JSON;

my $x =  from_json qx#lsblk -fJ#;

warn Dumper($x);

foreach my $disk ( @{$x->{blockdevices}} ) {

        # warn Dumper \$disk;
        foreach my $slice ( @{$disk->{children}} ) {

                while ( my ($k, $v) = each %{$slice}) {
                        print "$k = $v\n";
                }
        }
}



All times are GMT -5. The time now is 05:30 AM.