in reply to Open Filehandle once

Hello Dunkellbusch,

Welcome to the Monastery. The monks have already provided you with solutions to your problem, but I would like to add one more. You can use the module File::Slurp/append_file, so you can minimize your code to simply one call in every time you need it, no closing file handles etc.

But to be honest I would combine the module with the nice solution of fellow monk Corion, executable sample bellow below (change grep from /enable/ to /smb\.service/):

#!/usr/bin/perl use strict; use warnings; use File::Slurp; my $filePath = 'test_1.txt'; my @services = `systemctl list-unit-files`; if( my @smb = grep { /enabled/ } @services ) { map { s/\s+\z// } @smb; # remover white space append_file( $filePath, "chkconfig smb: OK\n"); append_file( $filePath, map { "$_\n" } @smb); # append_file( $filePath, "\n"); # if you want to append multiple +times }

Update: Based on comments try to avoid File::Slurp, for simple implementations (read, write, etc) you can use File::Slurper, unfortunately there the author has not added the append proposal. I was looking online and I found the IO::All. Never used it before but I read that it is really really good.

Sample of updated solution, based on commends:

#!/usr/bin/perl use strict; use warnings; use IO::All -utf8; # Turn on utf8 for all io my $path = 'file.txt'; my @services = `systemctl list-unit-files`; if( my @smb = grep { /enabled/ } @services ) { s{ ^\s* | \s*$ }{}gx for @smb; io($path)->appendln(@smb); }

Output:

$ cat test_1.txt chkconfig smb: OK acpid.path enabled cups.path enabled accounts-daemon.service enabled anacron-resume.service enabled anacron.service enabled apparmor.service enabled autovt@.service enabled avahi-daemon.service enabled bluetooth.service enabled console-setup.service enabled cron.service enabled cups-browsed.service enabled cups.service enabled dbus-org.bluez.service enabled dbus-org.freedesktop.Avahi.service enabled dbus-org.freedesktop.ModemManager1.service enabled dbus-org.freedesktop.nm-dispatcher.service enabled dbus-org.freedesktop.resolve1.service enabled dbus-org.freedesktop.thermald.service enabled denyhosts.service enabled display-manager.service enabled dns-clean.service enabled friendly-recovery.service enabled getty@.service enabled gpu-manager.service enabled keyboard-setup.service enabled lightdm.service enabled ModemManager.service enabled network-manager.service enabled networking.service enabled NetworkManager-dispatcher.service enabled NetworkManager-wait-online.service enabled NetworkManager.service enabled ondemand.service enabled openvpn.service enabled pppd-dns.service enabled repowerd.service enabled resolvconf.service enabled rsync.service enabled rsyslog.service enabled setvtrgb.service enabled snapd.autoimport.service enabled snapd.core-fixup.service enabled snapd.service enabled snapd.system-shutdown.service enabled ssh.service enabled sshd.service enabled syslog.service enabled systemd-resolved.service enabled systemd-timesyncd.service enabled thermald.service enabled ufw.service enabled unattended-upgrades.service enabled ureadahead.service enabled vboxautostart-service.service enabled vboxballoonctrl-service.service enabled vboxdrv.service enabled vboxweb-service.service enabled acpid.socket enabled apport-forward.socket enabled avahi-daemon.socket enabled cups.socket enabled snapd.socket enabled uuidd.socket enabled remote-fs.target enabled apt-daily.timer enabled motd-news.timer enabled snapd.refresh.timer enabled

Hope this helps, BR.

Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re^2: Open Filehandle once
by zentara (Cardinal) on Aug 24, 2017 at 17:51 UTC

      Hello zentara,

      Thanks for the commend, I remember that I read about it somewhere but I forgot. See my updated answer, BR.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re^2: Open Filehandle once
by 1nickt (Canon) on Aug 24, 2017 at 22:00 UTC

    Hello thanos1983,

    Please do not recommend File::Slurp. It's broken and wrong.

    Also please do not recommend using map in void context. This is considered bad practice by many programmers since you are only making the call for its side-effects whilst throwing away its output.


    The way forward always starts with a minimal test.
      "Also please do not recommend using map in void context."

      In general, I agree with this statement.

      "This is considered bad practice by many programmers since you are only making the call for its side-effects whilst throwing away its output."

      However, I disagree with this reason.

      The issue with "throwing away its output" was resolved, about 14 years ago[perlhist], in Perl 5.8.1. From "perl581delta: Miscellaneous Enhancements":

      "map in void context is no longer expensive. map is now context aware, and will not construct a list if called in void context."

      The reason I would give for not using map in void context is based on efficiency. I've had reason to benchmark map vs. for on a number of occasions over the years: I've always found for to be measurably faster than map; and, unsurprisingly, map EXPR is faster than map BLOCK.

      Here's a very quick and dirty benchmark I just wrote to show this:

      #!/usr/bin/env perl use strict; use warnings; use Benchmark 'cmpthese'; my @x = 0 .. 99; cmpthese 1e6 => { map_expr => sub { my @y = @x; map ++$_, @y; return }, map_block => sub { my @y = @x; map { ++$_ } @y; return }, for => sub { my @y = @x; ++$_ for @y; return }, };

      I ran this five times. All results were much the same. This one was roughly in the middle:

      Rate map_block map_expr for map_block 75019/s -- -44% -47% map_expr 134953/s 80% -- -5% for 141844/s 89% 5% --

      Benchmark run using:

      $ perl -v | head -2 | tail -1 This is perl 5, version 26, subversion 0 (v5.26.0) built for darwin-th +read-multi-2level

      — Ken

        "map in void context is no longer expensive. map is now context aware, and will not construct a list if called in void context."

        Hi Ken, I wasn't referring to "throwing away the output" in terms of wasted resources, but rather in terms of unclear code.

        map is a function that returns a list -- when it is used in void context it smells bad, because it forces the reader to double-check that the author didn't make a mistake, falling into the same general category as any other distracting syntax or idiom.

        It's also a bad habit in general to use functions for their side effects, as those may change.


        The way forward always starts with a minimal test.

        Timings could change from one version of perl to the next, so this kind of micro-optimization is meh. I would tend to use for over map myself in this situation, but it doesn't seem to matter all that much at this point. Whatever you do, don't write this:

        @smb = map { s/\s+\z//; $_ } @smb;

        Yes, I've seen people who habitually write this kind of thing. I don't know where they learned it.

      Hello 1nickt,

      You are right I completely forgot about it. Thanks for the observation of map also. See my updated answer, BR.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re^2: Open Filehandle once (updated)
by soonix (Chancellor) on Aug 25, 2017 at 08:49 UTC
    regarding File::Slurp alternatives, I like Path::Tiny, which has an append method, too.

    syntax would be e.g.

    use Path::Tiny (); # otherwise 'path' will be imported ... Path::Tiny::path($filePath)->append(map { "$_\n" } 'chkconfig smb: OK' +, @smb))