I am trying to read in a template config file (template.config) that looks like this:
;;path to speedseq package binary directory
$;SPEEDSEQ_BIN_DIR$; = /usr
This answer responds more directly to a related question. That is marked as "duplicate" of this one, while the existing answer here cannot handle that question, thus this answer. For the requirements and input file format please see the link. In short: There are multiple sections (like the one here) and order of lines within the section need be kept, as well as the order of sections.
There are a few components to this.
User input has to be organized somehow. We can provide a set of named options, and a translation of option names to corresponding lines in the input file. This is done using a particular Getopt option, along with a translation hash. (It can be organized in yet another way.)
A pair of lines identify where to apply user input, and their order need be maintained. For this we can use an array-ref for lines, being a value for the section-name key for the hash. The array keeps the order. The hash is not necessary (it can all be in one big array) but provides flexibility for future. The order of sections in the hash is maintained in a separate array. (Or one can add that to the hash.)
All supported options must be explicitly listed in the file. Here we define two.
use warnings;
use strict;
use Getopt::Long;
use feature qw(say);
# Translate user input <--> description line (;;) in file
my ($o1, $o2) = qw(o1 o2);
my %desc = (
$o1 => 'Sequence file 1',
$o2 => 'Output Chromosome',
# ...
);
my %input;
GetOptions(\%input, "$o1=s", "$o2=s");
my $config_file = 'config.txt';
open my $in_fh, '<', $config_file;
my (%conf, @mod_order, $mod_name, $des, $enter_input);
while (my $line = <$in_fh>)
{
chomp($line);
next if $line =~ m/^\s*$/;
# Name of new section ([]), for hash and order-array
if ($line =~ m/^\[(.*)\]$/) {
push @mod_order, $mod_name = $1;
}
# A description (;;) line
if ( ($des) = $line =~ m/^;;(.*)/ ) {
# Check for input and remember it for next iteration
for (keys %desc) {
if (exists $input{$_} and $des =~ /^$desc{$_}/) {
$enter_input = process_input($desc{$_}, $input{$_});
last;
}
}
# Keep the description line, it need be printed too
push @{$conf{$mod_name}}, $line . "\n";
next;
}
if ($enter_input) {
# Overwrite what is there or append
$line =~ s/(.*?=)(.*)/$1 $enter_input/;
$enter_input = '';
}
push @{$conf{$mod_name}}, $line . "\n";
}
close $in_fh;
say @{$conf{$_}} for @mod_order;
# In case user's raw input need be processed further
sub process_input {
my ($desc, $raw_input) = @_;
# Example (comment): prepend path for `Chromosome` input
# if ($desc =~ /Ouput Chromosome/) {
# return '/data/usr/' . $raw_input;
# else {
return $raw_input;
# }
}
The program can be invoked with at most the two provided options, or either, or none.
script.pl -o1 INPUT_FOR_FILE_SEQ_1 -o2 INPUT_FOR_CHROMO
Curtesy of Getopt::Long
all manner of malformed input is detected. The input file is hard-coded but it can be another command-line option or read in via < config.txt
. Instead of printing to screen the file can be overwritten in the program, or the print redirected.