Re: One to one file output idiom
by haukex (Archbishop) on Jan 15, 2020 at 18:10 UTC
|
I think your solution is fine. If you want to get fancy, you could use my Tie::Handle::Argv, which is the basis of my File::Replace::Inplace, an emulation of the -i switch (note: Perl v5.16 strongly recommended):
use warnings;
use 5.016;
package Tie::Handle::FancyThingy {
use parent 'Tie::Handle::Argv';
use File::Basename qw/fileparse/;
sub OPEN {
my ($self, $origfn) = @_;
my ($fn, $dirs, $ext) = fileparse($origfn, qr/\.[^\.]+$/);
my $outfn = $dirs.$fn.'.out';
print STDERR "Debug: $origfn => $outfn\n";
open ARGVOUT, '>', $outfn or die "$outfn: $!";
select ARGVOUT;
return $self->SUPER::OPEN($origfn);
}
sub inner_close {
my $self = shift;
select STDOUT;
return $self->SUPER::inner_close(@_);
}
}
tie *ARGV, 'Tie::Handle::FancyThingy';
while (<>) {
chomp;
say translate($_);
}
sub translate { return "<".shift.">" }
A more simplistic approach might be to just use the -i switch to write the "backup" (input) files to a different directory and then rename the output afterwards.
Minor edit to code: Replaced my $ofh (output filehandle) with the more appropriate ARGVOUT. | [reply] [d/l] [select] |
|
| [reply] |
Re: One to one file output idiom
by 1nickt (Canon) on Jan 15, 2020 at 18:15 UTC
|
Hello Eily, I use Path::Tiny for almost all the file things.
$ rm foo* bar*
$ echo foo > foo
$ echo bar > bar
$ perl -MPath::Tiny -wnE 'sub baz {uc} chomp; my $in = path($_); $in->
+sibling("$_.new")->spew(baz($in->slurp));' foo bar
$ cat foo.new
FOO
$ cat bar.new
BAR
Hope this helps!
The way forward always starts with a minimal test.
| [reply] [d/l] [select] |
|
Is it just me or are the method names of this module really not helfpul? I had to loop spew in the dictionary because I wasn't sure of the implication, I knew of "spewing nonsense" but I didn't realize the word had such a negative connotation to it. And somehow I would understand spew to be the reverse action (getting data out of a file, not in). And I got what sibling does because I knew what to expect. Beyond that I guess it is a pretty short and "clean" (except for the confusing names) way to do what I want.
Also, here your code works because each file contains its own name, but I think it should be path(shift), without the -n option
| [reply] |
|
| [reply] |
|
|
|
|
Re: One to one file output idiom
by choroba (Cardinal) on Jan 15, 2020 at 17:52 UTC
|
Another suggestion of mine form the CB discussion:
perl -pwe 'open STDOUT, ">", "$ARGV.txt" if $last ne $ARGV; s/.*/\U$&/
+; $last = $ARGV' *.obj
Update:
Using eof is a bit cleaner, but it still triggers at a wrong time, so it couldn't be used directly:
perl -pwe 'open STDOUT, ">", "$ARGV.txt" unless $e; $e = ! eof; s/.*/\
+U$&/' *.obj
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
maybe try $. to catch the first line per file, like
C:\tmp\files>perl -nE"say qq($.--$ARGV) if $.==1; $.=0 if eof " a b c
1--a
1--b
1--c
Unfortunately I need to reset $. at the end of each file, which is kind of hacky! :/
| [reply] [d/l] [select] |
|
Closing ARGV before it gets opened again would be the non hacky thing way to do it since it's shown in the doc, although it's a bit longer.
Edit: choroba pointed out it was shown in the doc for eof not open
| [reply] |
Re: One to one file output idiom
by tybalt89 (Monsignor) on Jan 15, 2020 at 22:39 UTC
|
perl -MPath::Tiny -n0e 'sub translate {map tr/a-z/A-Z/r, @_} path($ARG
+V =~ s/in$/out/r)->spew(translate($_))' *.in
I had to fake a translate() to test it...
| [reply] [d/l] |
Re: One to one file output idiom
by shmem (Chancellor) on Jan 15, 2020 at 20:30 UTC
|
Just open a new file whenever the current $ARGV isn't the same as the remembered one (which can be undefined):
perl -p -e '$o ne $ARGV and open STDOUT,">","$ARGV.out" and $o = $ARGV
+; s/perl6/raku/;' foo bar baz
When the input file changes ($ARGV), a new output file is opened. Of course, a file can be run instead of -e '$proggy'.
perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
| [reply] [d/l] [select] |
Re: One to one file output idiom
by LanX (Sage) on Jan 15, 2020 at 18:11 UTC
|
as I suggested in the CB do the open explictely:
I'm not good with one-liners, but this seems to do the job on Windows
>perl -pE"open OUT => qq(>$ARGV.ext); select (OUT); s/bla/drivel/" a b
+ c
| [reply] [d/l] [select] |
|
Does it work if the files have more than one line? It seems the open overwrites the output file every time...
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
|
No, but >> for append does, though you must be sure the OUT-file doesn't exist already
C:\tmp\files>perl -pE"open STDOUT=>qq(>>$ARGV.ext); s/bla/drivel/" a b
+ c
There was a hack with Eskimo kiss } { in the -e but as I said I'm not experienced with one liners.
| [reply] [d/l] [select] |
|
|
|
Re: One to one file output idiom
by LanX (Sage) on Jan 16, 2020 at 18:04 UTC
|
After a lot of trying I'm convinced there is no justified one-liner solution.
Any approach is either unclean, vulnerable or so "golfy", that a multi-line script is to be preferred.
If I were you, I'd propose a new Perlrun option -o to change the output file the same way -i is changing the input.
This would be very "orthogonal" and allow to combine both options in the same run.
| [reply] |
Re: One to one file output idiom
by LanX (Sage) on Jan 15, 2020 at 23:50 UTC
|
I was playing around (and abusing) the debugger as shell. ;)
That's what I got so far, not perfect though
C:\tmp\files>set TERM=dumb
C:\tmp\files>perl -dE0
Loading DB routines from perl5db.pl version 1.49_05
Editor support available.
Enter h or 'h h' for help, or 'perldoc perldebug' for more help.
main::(-e:1): 0
DB<1> sub out { if ($.==1) { open(ARGVOUT,">","$ARGV".shift); select
+ (ARGVOUT) } ; $. = "0 EOF at $." if eof }
DB<2> x @ARGV=<?>
0 'a'
1 'b'
2 'c'
DB<3> x <>
0 '1:bla bla
'
1 '2:bla bla
'
2 '3:bla bla
'
3 '1:bla bla
'
4 '2:bla bla
'
5 '3:bla bla
'
6 '1:bla bla
'
7 '2:bla bla
'
8 '3:bla bla
'
DB<4> x @ARGV=<?>
0 'a'
1 'b'
2 'c'
DB<5> print s/bla/drivel/r while (<>)
1:drivel bla
2:drivel bla
3:drivel bla
1:drivel bla
2:drivel bla
3:drivel bla
1:drivel bla
2:drivel bla
3:drivel bla
DB<6> x @ARGV=<?>
0 'a'
1 'b'
2 'c'
DB<7> out(".ext"), print s/bla/drivel/r while (<>)
DB<8> x @ARGV=<?.ext>
0 'a.ext'
1 'b.ext'
2 'c.ext'
DB<9> x <>
0 '1:drivel bla
'
1 '2:drivel bla
'
2 '3:drivel bla
'
3 '1:drivel bla
'
4 '2:drivel bla
'
5 '3:drivel bla
'
6 '1:drivel bla
'
7 '2:drivel bla
'
8 '3:drivel bla
'
DB<10>
| [reply] [d/l] |