Split Nagios configuration into multiple files - file

NagiosQL creates a file called servicetemplates.cfg.
For easier distribution of some selected templates I' d like to split any service definition into one seperate file.
Sample servicetemplates.cfg
define service {
name imap_service
use generic_service
check_command check_service_imap
register 0
}
define service {
name ldapserver_ldap_service
service_description LDAP
use generic_service
check_command check_service_ldap
icon_image ldapserver.png
register 0
}
What I like to have is some kind of parser, which create files like the "name" of the template, e. g. imap_service.cfg and ldapserver_ldap_service.cfg.
Every file have to include the whole definition (define service { ... } )

The following code is a solution for me, it might not be perfect as it expects a certain syntax of the Nagios object configuration.
The first parameter has to be the file name of the Nagios configuration file.
<?php
if (empty($argv[1])) {
echo "First parameter: File to Nagios object configuration\n";
exit(1);
}
$starttag=0;
$outfile='';
$outtext='';
$inputfile=$argv[1];
$cfgfile = file($inputfile) or exit(2);
foreach ($cfgfile as $line_num => $line) {
# $outtext will be reset if define ... { is found
$outtext.=$line;
# Start tag of a new section "define ... {"
if (preg_match("/.*define.*{/i", $line)) {
$starttag=1;
$outtext=$line;
}
# Split the line with name. The parameter after name is the later filename
if (preg_match("/name[\s]+[\w]+/", $line) && $starttag=1) {
$keywords=preg_split("/[\s]+/", $line);
$outfile=$keywords[2];
$outfile.=".cfg";
$outfile=str_replace(' ', '_', $outfile);
}
# End tag of a new section "}"
if (preg_match("/.*}/", $line) && $starttag=1) {
$starttag=0;
echo "Writing {$outfile}\n";
file_put_contents($outfile, $outtext);
}
}
echo "Read lines {$line_num} from {$inputfile}\n";
?>

Related

Cache file content and then extract matches using regex

Please forgive a bash newbie for any silly questions.
I am really stuck here and I would love to know how this works and what I am doing wrong.
I have written this script which is supposed to capture syslog server based on protocol.
The input is as follows:
sys syslog {
include "destination remote_server {tcp(\"10.1.0.100\" port (514));tcp(\"192.168.1.5\" port (514));udp(\"192.168.1.60\" port (514));};filter f_alllogs {level (debug...emerg);};log {source(local);filter(f_alllogs);destination(remote_server);};"
remote-servers {
mysyslog {
host 192.168.1.1
}
remotesyslog1 {
host 192.168.1.2
}
remotesyslog2 {
host 192.168.1.3
local-ip 10.0.0.50
}
}
}
From this I would like to get something like in the end:
tcp=10.1.0.100
tcp=192.168.1.50
udp=192.168.1.60
udp=192.168.1.1
udp=192.168.1.2
udp=192.168.1.3
So I started with a bash script to parse the output.
#!/bin/bash
#Save output to file
syslogoutput=$(< /home/patrik/input)
echo "Testing variable:"
echo $syslogoutput
echo ""
#Declare array
tcpservers=()
echo $syslogoutput | while read line ; do
matches=($(echo $line | grep -Po '(tcp\("[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}")'))
#If number of matches is greater than 0, save them to tcpservers
if [ ${#matches[#]} -gt 0 ]; then
tcpservers=("${matches[#]}")
#Echoing matches
echo "Testing matches in loop:"
for i in "${matches[#]}"; do
echo $i
done
fi
done
echo "Testing output:"
for i in "${tcpservers[#]}"; do
echo $i
done
I expected something like this:
...input file separated by line breaks
Testing matches in loop:
tcp("10.1.0.100"
tcp("192.168.1.5"
Testing output:
tcp("10.1.0.100"
tcp("192.168.1.5"
But instead I get:
sys syslog { include "destination remote_server {tcp(\"10.1.0.100\" port (514));tcp(\"192.168.1.5\" port (514));udp(\"192.168.1.60\" port (514));};filter f_alllogs {level (debug...emerg);};log {source(local);filter(f_alllogs);destination(remote_server);};" remote-servers { mysyslog { host 192.168.1.1 } remotesyslog1 { host 192.168.1.2 } remotesyslog2 { host 192.168.1.3 local-ip 10.0.0.50 } } }
Testing matches in loop:
tcp("10.1.0.100"
tcp("192.168.1.5"
Testing output:
So on to my questions:
Why isn't tcpservers=("${matches[#]}") working?
Why isn't the output cached with line breaks?
Why does bash scripting make me want to jump from a tall building every time I try it?
/Patrik
Don't use redirection, as it starts the loop in a subshell, and variables form a subshell don't propagate into the parent shell.
while read line ; do
# ...
done <<< "$syslogoutput"
You also overwrite the tcpservers on each iteration. Change the assignment to
tcpservers+=("${matches[#]}")
# ^
# |
# add to an array, don't overwrite

I want remove file extension or rename the file extension before uploaded in php codeigniter

when user select the file then in server side file extension will be removed or rename and uploaded it to the server using php codeigniter library
This should remove your file extension
<?php
$var = "testfile.php";
$explode = explode( '.', $var );
array_pop( $explode);
$var = implode( '.', $explode );
var_dump( $var );
As for uploading you will need to read the manual on file uploading
http://www.codeigniter.com/user_guide/libraries/file_uploading.html
file name can be changed using the following codes:
$your_given_name = time().rand().$_FILES["userfiles"]['name'];
$config['file_name'] = $your_given_name;
for changing extension you can use:
if ($this->upload->do_upload('file_name')) {
$file_data=$this->upload->data();
$new_name_by_you='anything'.$file_data['file_ext'];
$new_path=$file_data['file_path'].$new_name_by_you;
rename($file_data['full_path'], $new_path);
}
rename() is a php built in function. for details please visit http://php.net/manual/en/function.rename.php
I recently just had the same issue, and found it really annoying that even when you specified a file_name in code igniter it would append the file extension. Which i did not want.
Blinkydamo's link is not helpfull, since that is the link i was following in the first place and makes no mention of this dilema, although it does demontrate that it is not possible idrectly through Code Igniter - by ommission of the answer.
I haven't tried md asif rahman's method, but it looks sound.
Alternatively you can just forget about using Code Igniter's upload function, and fall back onto PHPs standard one, which is what I have done :
move_uploaded_file($_FILES['imageFile']['tmp_name'], '/path/'.$filename);
where $filename is the exact name of the file including extension, therefore if none is specified - it wont have one.
it is so easy
change code in
libraries/Upload.php
public function set_filename($path, $filename)
{
if ($this->encrypt_name === TRUE)
{
$filename = md5(uniqid(mt_rand()));
}
if ($this->overwrite === TRUE OR ! file_exists($path.$filename))
{
return $filename;
}
$filename = str_replace($this->file_ext, '', $filename);
$new_filename = '';
for ($i = 1; $i < $this->max_filename_increment; $i++)
{
if ( ! file_exists($path.$filename.$i))
{
$new_filename = $filename.$i;
break;
}
}
if ($new_filename === '')
{
$this->set_error('upload_bad_filename', 'debug');
return FALSE;
}
else
{
return $new_filename;
}
}

PHP if file exists, always show that exists

I have database columns attach1 and attach2.
I need to show files (pdf) from those columns, but only if they exist in directory www.domain.com/uploads.
Attach1 contains real file but attach2 does not.
I tried something like this:
<?php
$file = $row['attach'];
$exists = file_exists('uploads/'.$file.'');
if ($exists) {
echo $file;
}
if (!$exists) {
echo 'No file1';
}
?>
<?php
$file2 = $row['attach2'];
$exists = file_exists('uploads/'.$file2.'');
if ($exists) {
echo $file2;
}
if (!$exists) {
echo 'No file2';
}
?>
But everytime it echoes me back, that file exists, even when attach2 contains nothing. Why?
If your filename is empty, then you are passing only the directory name to file_exists. Directories are files too. And I reckon the directory does actually exist. It is not lying to you.
You can either check that the filename from the database is not empty, or you can pass the whole string to the function is_dir to see if it is a directory. I assume you only want regular files.
That would look something like this:
<?php
$file = $row['attach'];
$exists = file_exists('uploads/'.$file.'') && !is_dir('uploads/'.$file.'');
if ($exists) {
echo $file;
} else {
echo 'No file1';
}
?>
I changed the if statement to use an else clause. It is equivalent to using a second if like you did.

uniquely rename each of many files using perl

I have a folder containing 96 files that I want to rename. The problem is that each file name needs a unique change...not like adding a zero the front of each name or changing extensions. It isn't practical to do a search and replace.
Here's a sample of the names I want to change:
newSEACODI-sww2320H-sww24_07A_CP.9_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07B_CP.10_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07C_CP.11_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07D_CP.12_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07E_R.1_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07F_R.3_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07G_R.4_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07H_R.5_sww2320H_sww2403F.fsa
I'd like to use perl to change the above names to the below names, respectively:
SEACODI_07A_A.2_sww2320H_2403F.fsa
SEACODI_07B_A.4_sww2320H_2403F.fsa
SEACODI_07C_H.1_sww2320H_2403F.fsa
SEACODI_07D_H.3_sww2320H_2403F.fsa
SEACODI_07E_H.6_sww2320H_2403F.fsa
SEACODI_07F_H.7_sww2320H_2403F.fsa
SEACODI_07G_Rb.4_sww2320H_2403F.fsa
SEACODI_07H_Rb.9_sww2320H_2403F.fsa
Can such a thing be done? I have a vague idea that I might make a text file with a list of the new names and call that list #newnames. I would make another array out of the current file names, and call it #oldnames. I'd then do some kind of for loop where each element $i in #oldnames is replaced by the corresponding $i in #newnames.
I don't know how to make an array out of my current file names, though, and so I'm not sure if this vague idea is on the right track. I keep my files with the messed-up names in a directory called 'oldnames'. The below is my attempt to make an array out of the file names in that directory:
#!/usr/bin/perl -w
use strict; use warnings;
my $dir = 'oldnames';
opendir ('oldnames', $dir) or die "cannot open dir $dir: $!";
my #file = readdir 'oldnames';
closedir 'oldnames';
print "#file\n";
The above didn't seem to do anything. I'm lost. Help?
Here:
#!/usr/bin/perl
use warnings;
use strict;
use autodie;
use File::Copy;
# capture script name, in case we are running the script from the
# same directory we working on.
my $this_file = (split(/\//, $0))[-1];
print "skipping file: $this_file\n";
my $oldnames = "/some/path/to/oldnames";
my $newnames = "/some/path/to/newnames";
# open the directory
opendir(my $dh, $oldnames);
# grep out all directories and possibly this script.
my #files_to_rename = grep { !-d && $_ ne $this_file } readdir $dh;
closedir $dh;
### UPDATED ###
# create hash of file names from lists:
my #old_filenames = qw(file1 file2 file3 file4);
my #new_filenames = qw(onefile twofile threefile fourfile);
my $filenames = create_hash_of_filenames(\#old_filenames, \#new_filenames);
my #missing_new_file = ();
# change directory, so we don't have to worry about pathing
# of files to rename and move...
chdir($oldnames);
mkdir($newnames) if !-e $newnames;
### UPDATED ###
for my $file (#files_to_rename) {
# Check that current file exists in the hash,
# if true, copy old file to new location with new name
if( exists($filenames->{$file}) ) {
copy($file, "$newnames/$filenames->{$file}");
} else {
push #missing_new_file, $file;
}
}
if( #missing_new_file ) {
print "Could not map files:\n",
join("\n", #missing_new_file), "\n";
}
# create_hash_of_filenames: creates a hash, where
# key = oldname, value = newname
# input: two array refs
# output: hash ref
sub create_hash_of_filenames {
my ($oldnames, $newnames) = #_;
my %filenames = ();
for my $i ( 0 .. (scalar(#$oldnames) - 1) ) {
$filenames{$$oldnames[$i]} = $$newnames[$i];
}
# see Dumper output below, to see data structure
return \%filenames;
}
Dumper result:
$VAR1 = {
'file2' => 'twofile',
'file1' => 'onefile',
'file4' => 'fourfile',
'file3' => 'threefile'
};
Running script:
$ ./test.pl
skipping file: test.pl
Could not map files:
a_file.txt
b_file.txt
c_file.txt
File result:
$ ls oldnames/
a_file.txt
b_file.txt
c_file.txt
file1
file2
file3
file4
$ ls newnames/
fourfile
onefile
threefile
twofile
Your code is a little odd, but it should work. Are you running it in the directory "oldnames" or in the directory above it? You should be in the directory above it. A more standard way of writing it would be like this:
#!/usr/bin/perl -w
use strict; use warnings;
my $dir = 'oldnames';
opendir ( my $oldnames, $dir) or die "cannot open dir $dir: $!";
my #file = readdir $oldnames;
closedir $oldnames;
print "#file\n";
This would populate #files with all the files in oldnames, including '.' and '..'. You might need to filter those out depending on how you do your renaming.
Can you do this with rename? It does allow you to use perl code and expressions as arguments if I recall.
The real answer is the one by #chrsblck it does some checks and doesn't make a mess.
For comparison here is a messy one liner that may suffice. It relies on you providing a list of equivalent new file names that will rename your list of old files in the correct order. Perhaps for your situation (where you don't want to do any programmatic transformation of the files names) you could just use a shell loop (see the end of this post) reading lists of new and old names from a file. A better perl solution would be to put both of these file name lists into two columns and then that file using the -a switch , #F and then useFile::Copy to copy the files around.
Anyway, below are some suggestions.
First, set things up:
% vim newfilenames.txt # list new names one per line corresponding to old names.
% wc -l newfilenames.txt # the same number of new names as files in ./oldfiles/
8 newfilenames.txt
% ls -1 oldfiles # 8 files rename these in order to list from newfilenames.txt
newSEACODI-sww2320H-sww24_07A_CP.9_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07B_CP.10_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07C_CP.11_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07D_CP.12_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07E_R.1_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07F_R.3_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07G_R.4_sww2320H_sww2403F.fsa
newSEACODI-sww2320H-sww24_07H_R.5_sww2320H_sww2403F.fsa
With files arranged as above, copy everything over:
perl -MFile::Copy -E 'opendir($dh , oldfiles); #newfiles=`cat newfilenames.txt`; chomp #newfiles; #oldfiles = sort grep(/^.+\..+$/, readdir $dh); END {for $i (0..$#oldfiles){copy("oldfiles/$oldfiles[$i]", "newfiles/$newfiles[$i]"); }}'
Not pretty: you have to grep andsort on #oldfiles to get rid of . .. and put the array elments in order. And there's always the risk that a typo could make a mess and it would be hard to figure out.
If you put the old and new names in a couple of files you could just do this with this with a shell script:
for i in `cat ../oldfilenames.txt` ; do ; done; for n in `cat ../newfilenames.txt`; do cp $i $n;
or just cd into the directory with the old files and do:
mkdir new
for i in * ; do ; done; for n in `cat ../newfilenames.txt`; do cp $i new/$n;
Good luck!

How to assign two arrays to a hash and correlate them by name basis in Perl

I've got two arrays, both consisting of a list of filenames. The filenames are identical in both arrays except for the extension.
i.e. filename.dwg and filename.zip
Now, I've assigned each list of files to an array.
i.e. #dwg_files and #zip_files
Ultimately, what I'm trying to do is check last modification date between two files of the same name in different arrays, then run a script if one is younger than they other. What I have so far seems to work except when it compares two files with different names. I need it to compare a file from the first array to the identical file in the other array.
i.e. asdf1.dwg should be correlated to asdf1.zip
my $counter = 0 ;
while ( $counter < #dwg_files ) {
print "$counter\n";
my $dwg_file = $dwg_files[$counter];
my $zip_file = $zip_files[$counter];
#check if zip exists
if (-e $zip_file) {
#Checks last modification date
if (-M $dwg_file < $zip_file) {
*runs script to creat zip*
} else {
*Print "Does not need update."*
}
} else {
*runs script to create zip*
}
$counter++;
}
Doing some research, I figured I'd try to use a hash to correlate the two arrays. I just can't seem to figure out how to correlate them by name.
my %hash;
#hash{#dwg_files} = #zip_files;
I'm a complete Perl noob (just started working with it last week). I've been stuck on this for days, any help would be much apprecieted!
You could take dwg file name, change extension to zip, and then proceed with checks,
for my $dwg_file (#dwg_files) {
my $zip_file = $dwg_file;
print "dwg:$dwg_file\n";
$zip_file =~ s/[.]dwg/.zip/i or next;
#check if zip exists
if (-e $zip_file) {
#Checks last modification date
if (-M $dwg_file < -M $zip_file) {
#*runs script to creat zip*
} else {
#*Print "Does not need update."*
}
} else {
#*runs script to create zip*
}
}
To store all of the filenames in a hash, you could do something like this:
#!/usr/bin/perl
use Data::Dumper;
# grab all dwg and zip files
my #dwg_files = glob("*.dwg");
my #zip_files = glob("*.zip");
sub hashify {
my ($dwg_files, $zip_files) = #_;
my %hash;
# iterate through one of the arrays
for my $dwg_file ( #$dwg_files ) {
# parse filename out
my ($name) = $dwg_file =~ /(.*)\.dwg/;
# store an entry in the hash for both the zip
# and dwg files
# Entries of the form:
# { "asdf1" => ["asdf1.dwg", "asdf1.zip"]
$hash{$name} = ["$name.dwg", "$name.zip"];
}
# return a reference to your hash
return \%hash;
}
# \ creates a reference to the arrays
print Dumper ( hashify( \#dwg_files, \#zip_files ) );
This is what the resulting hash looks like:
{
'asdf3' => [
'asdf3.dwg',
'asdf3.zip'
],
'asdf5' => [
'asdf5.dwg',
'asdf5.zip'
],
'asdf2' => [
'asdf2.dwg',
'asdf2.zip'
],
'asdf4' => [
'asdf4.dwg',
'asdf4.zip'
],
'asdf1' => [
'asdf1.dwg',
'asdf1.zip'
]
};

Resources