PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : need help um perl script zu ändern


ccc
26.02.2004, 12:02
hi

brauche dringend hilfe
ich bekomme 3 files: ein info file und zwei data files ( alle csv Textdateien )
ca. 5 mal am tag zugeschickt:

info
CC1000022
DD1000022

info file sieht so aus:
-------------------------------------
CC1000022 DD000000011

DD1000022 EE0000000012
-------------------------------------

info file wechselt nie den namen, die andere files aber ja.
im info file oben ist immer erste file und unten der zweite.
zuerst muss ich der info file aufmachen und die beiden files
umbenennen :

CC1000022 in DD000000011
DD1000022 in EE0000000012

anschliessend die beiden umbenannten files:
zuerst aber CC1000022 und 10 minuten später DD1000022
per ftp zu einem anderem server schicken.
dabei 3 sachen sind sehr wichtig:
1.) der zweite file darf nicht vor dem ersten file geschickt werden
2.) zweite file darf nicht früher als 3 minuten nachdem der erste file geschicht wurde.
3.) 2 file darf nicht geschickt werden wenn der erste nicht gteschickt wurde

ich habe da ein perl script:

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

# open and read info file
@ARGV = ("info");
my %ren;
while (<>) { # for every line in info
m/^\s*(\S+)\s+(\S+)\s*$/ or next; # That matches like "CC1000022 DD1000022"
-f $1 or next; # skip if file to rename does not exist
-f $2 and next;
$ren{$1} = $2;
}

# check if files are complete
unless (2 == scalar keys %ren) {
die "files are NOT complete !\n";
}

# rename files according info file
foreach my $f1 (keys %ren) {
my $f2 = $ren{$f1};
move ($f1, $f2); # Rename files

# ftp transfer
my $server = "X.X.X.X";
my $user = "anonymous";
my $passwd = "";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ($user,$passwd) or
die "$_: Could not login: " . $ftp->message;

# Put file 2 (not 1) to the ftp server
$ftp->put ($f2) or
die "$server: cannot put $f2: " . $ftp->message;

# and wait 10 minutes
sleep (10 * 60);
}
mein problem ist , dass in meisten fällen wird der zweite
file zuerst geschickt.
wie kann ich dies ändern, damit der erste file immer
zuerst geschickt wird ?


Jan Krüger
26.02.2004, 12:25
Hi,

liegt daran, dass die Reihenfolge der Einträge in Hashes nicht definiert ist. Du kannst also nicht davon ausgehen, dass der Inhalt des Hashes beim Abrufen noch die gleiche Reihenfolge hat wie beim Eintragen.
Du kannst das Script alternativ in etwa so aufbauen (dadurch wird es auch kürzer und einfacher):

- info einlesen
- Für jeden Eintrag Datei umbenennen, hochladen und drei Minuten warten.

ccc
26.02.2004, 13:55
hallo jan

habe probiert.
haut irgendwie nicht hin.
kannst du bitte vielleicht mir ein paar zeilen code posten, wie ich für jeden eintrag einzeln umbenen könnte ?
mit ftp transfer commands sollte
selber klar kommen.

gruss
ccc

Jan Krüger
26.02.2004, 14:01
Ist doch kein Problem mit rename()...

ccc
26.02.2004, 14:07
sorry habe mich total falsch ausgedruckt,
meinte nicht umbenenen, sondern
die eintrage einzeln einzulesen.

Jan Krüger
26.02.2004, 14:10
Naja, so nach dem Motto:
while (<INFOFILE>) {
chomp;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# hier FTP-upload
}

ccc
26.02.2004, 15:22
danke, habe aber ein problem,
weil der file wird umbenannt statt
DD000000011
in
DD000000011□

weisst du vielleicht warum " □ "
angehängt wird ?
dadurch wird die datei irgendwie unbrauchbar und kann sie nicht einmal aufmachen ?

script:


#!/usr/bin/perl

use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

open(FILE, "<info>");
while (<FILE>) {
chomp;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# ftp transfer

my $server = "X.X.X.X";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ('anonymous', 'xxx@domain.net') or
die "$_: cannot logon: " . $ftp->message;

# Put first file to the ftp server
$ftp->put ($2) or
die "$server: cannot put $2: " . $ftp->message;

}


gruss
ccc

Jonas
26.02.2004, 17:25
mhm werden irgendwelche komischen zeilenumbruchzeichen sein, oder?

was is nochma genau der unterschied zwischen chomp und chop? probiers mal mit chop

man bin ich eingerostet

ccc
26.02.2004, 18:44
mit "chop" passiert das gleiche

gruss
ccc

Jan Krüger
27.02.2004, 09:42
Das liegt wahrscheinlich an den Windows-Codes für Zeilenumbruch. Probier statt chomp mal Folgendes:
s/\W*$//;

chomp unterscheidet sich von chop dadurch, dass chop immer das letzte Zeichen eines Strings entfernt und chomp nur dann, wenn es sich um einen Zeilenumbruch oder Ähnliches handelt.

ccc
27.02.2004, 12:08
herzlichen dank !

mit:

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

open(FILE, "<info>");
while (<FILE> ) {
s/\W*$//;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# ftp transfer

my $server = "X.X.X.X";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ('anonymous', 'xxx@domain.net') or
die "$_: cannot logon: " . $ftp->message;

# Put first file to the ftp server
$ftp->put ($2) or
die "$server: cannot put $2: " . $ftp->message;

}

die dateien werden jetzt richtig umbenannt !
aber das problem ist , dass sie beide fast auf einmal geschickt werden.

wie kann ich dieses script ändern, dass zuerst immer die erste datei, wie z.B DD000000011 ( dieser name ändert aber jedesmal )
geschickt wird, sicher sein dass sie angekommen ist und erst dann 3 minuten später die zweite.

gruss
ccc

Scavi
27.02.2004, 12:15
chomp nur dann, wenn es sich um einen Zeilenumbruch oder Ähnliches handelt.
Chomp entfernt das Zeichen, was in $/ steht, das muss nicht \n sein !

Jan Krüger
27.02.2004, 12:16
Okok. ;)

ccc: am Ende der Schleife ein entsprechend langes sleep() einfügen.

ccc
27.02.2004, 12:27
danke,

wäre es irgendwie möglich zu kontrolieren,
ob die erste datei 100% vollständig angekommen ist. z.B size der datei vergleichen und erst dann die zweite schicken ?

es ist etwas kompliziert, aber ich kann
wirklich die zweite datei nicht schicken,
wenn die erste gar nicht oder nicht vollständig
angekommen ist.

gruss
ccc

Jonas
27.02.2004, 13:43
ccc, gewöhn dir bitte die code-Tags an.

Du hast ja genug zeit, 3 Minuten - ist zwar eigentlich unsinnig, aber zieh doch einfach vom ftp die datei widerzum, und vergleich die beiden....

ccc
27.02.2004, 21:12
hallo Jonas

und wie soll das funktionieren ?
kannst du bitte ein paar zeilen code
posten ?
bin eben kein perl profi.

gruss
ccc

Jan Krüger
28.02.2004, 02:21
Deswegen gibt's ja die Doku - perldoc Net::FTP.

ccc
03.03.2004, 11:17
und wie kann ich ändern, dass das zweite file
zu einer anderen directory geschickt wird, z.B zu
$ftp->cwd("FTP/OUT"); ?


#!/usr/bin/perl

use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

open(FILE, "<info>");
while (<FILE> ) {
s/\W*$//;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# ftp transfer

my $server = "X.X.X.X";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ('anonymous', 'xxx@domain.net') or
die "$_: cannot logon: " . $ftp->message;

# change remote directory for the first file
$ftp->cwd("FTP/IN");

# Put first file to the ftp server
$ftp->put ($2) or
die "$server: cannot put $2: " . $ftp->message;

sleep (10 * 60)

}

Jan Krüger
03.03.2004, 11:47
Leg dir außerhalb der Schleife eine Variable à la "my $cwd_performed = 0;" an, und füg dann am Ende der Schleife sowas wie das hier ein:
$ftp->cwd(...) if (!$cwd_performed++);

ccc
04.03.2004, 00:04
hallo jan

habe etwas probiert, geht aber nicht.

verstehe aber nicht ganz.

gruss
ccc

Jonas
04.03.2004, 10:42
Benutz code-Tags, ccc!!!

Zu Jans Code: $cwd_performed ist anfangs 0, also "false", jedenfalls bei einer entsprechenden if-Abfrage.
Der Code oben bedeutet: Wenn $cwd_performed 0 ist -> cwd-Befehl ausführen. Anschließend (wichtig: ++ stehen HINTER der Variable, also wird erst ausgewertet, dann erhöht) $cwd_performed um eins erhöht.

Der cwd-Befehl wird also nur das allererste mal, einmal ausgeführt.

ccc
04.03.2004, 11:41
Hallo Jonas

sorry, habe die Code-Tags wirklich vergessen, aber nachträglich geändert.

kannst du bitte ein paar zeilen
code posten, wie das genau gemeint ist.

bei meinen versuchen klappt irgendwie
nicht und schickt immer beide files
in die gleiche directory.

gruss
ccc

Jonas
05.03.2004, 12:12
na, vor der while-Schleife die Variable $cwd_performed auf 0 setzen.
Dann deinen cwd-Befehl IN der Schleife entsprechend ändern, nach dem Prinzip das Jan gepostet hat (ich würde eine if-else-Schleife machen)

ccc
05.03.2004, 20:59
habe geändert, aber die files gehen
nach wie vor in die gleiche directory
und weiss nicht wo der hund begraben liegt .


#!/usr/bin/perl -w

use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

open(FILE, "<info>");
while (<FILE> ) {
s/\W*$//;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# ftp transfer

my $server = "X.X.X.X";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ('anonymous', 'xxx@domain.net') or
die "$_: cannot logon: " . $ftp->message;

# change remote directories
my $cwd_performed = 0;
if ($cwd_performed => 0) {
$ftp->cwd("FTP/IN")
}
else {
$ftp->cwd("FTP/OUT") if (!$cwd_performed++)
}

# Put first file to the ftp server
$ftp->put ($2) or
die "$server: cannot put $2: " . $ftp->message;

#Quit FTP when finished
$ftp->quit;

sleep (10 * 60)
}

Jan Krüger
06.03.2004, 13:34
Kein Wunder; du setzt die Variable ja auch in jedem Schleifendurchlauf wieder auf 0...

ccc
06.03.2004, 18:31
hallo Jan

danke für den hinweis,
aber ich fühle micht langsam irgendwie unsicher.

my $cwd_performed = 0;

if ($cwd_performed < 3) {

$ftp->cwd("/FTP/IN")

}

else {

$ftp->cwd("/FTP/OUT") if (!$cwd_performed++)

}
geht auch nicht.

Jan Krüger
06.03.2004, 19:45
Du setzt es mit dem "my" immer noch bei jedem Durchlauf auf 0. Du musst $cwd_performed komplett vor der Schleife initialisieren, sonst wird die Variable in jedem Durchlauf wieder mit dem Startwert 0 angelegt, und dann passiert natürlich nichts.

ccc
06.03.2004, 20:26
hallo Jan

wenn ich aber "my" wegnehme,
bekomme ich:

[Sat Mar 6 20:06:22 2004] ftp5.cgi: Global symbol "$cwd_performed" requires explicit package name at ftp5.cgi line 59.
[Sat Mar 6 20:06:22 2004] ftp5.cgi: Global symbol "$cwd_performed" requires explicit package name at ftp5.cgi line 61.
[Sat Mar 6 20:06:22 2004] ftp5.cgi: Global symbol "$cwd_performed" requires explicit package name at ftp5.cgi line 69.
[Sat Mar 6 20:06:22 2004] ftp5.cgi: Execution of ftp5.cgi aborted due to compilation errors.

irgendwie komme nicht weiter.

gruss
ccc

Jonas
06.03.2004, 21:00
du musst die Variable VOR der while-Schleife initialisieren, mit dem my drin.
VOR der while-Schleife, nicht IN der while-Schleife

ccc
06.03.2004, 22:18
hi Jan und Jonas

herzlichen dank !
mit :

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Copy;
use Net::FTP;
use Net::Netrc;

# change directory
chdir "/home/ftp/files" or die "/home/ftp/files: $!\n";

# DO NOT transfer without info file
-f "/home/ftp/files/info" or die "info file is missing\n";

open(FILE, "<info>");
my $cwd_performed = 0;
while (<FILE> ) {
s/\W*$//;
next if (!$_);
/^(.+?) \s+ (.+?)$/x;

my ($old, $new) = ($1, $2);
rename $old, $new;

# ftp transfer

my $server = "X.X.X.X";
my $ftp = Net::FTP->new ($server, Timeout => 9000, Debug => 3);
$ftp or die "$server: cannot connect: $@";
# If you don't use ~/.netrc
$ftp->login ('anonymous', 'xxx@domain.net') or
die "$_: cannot logon: " . $ftp->message;

# change remote directories
if ($cwd_performed > 0) {
$ftp->cwd("/FTP/OUT")
}
else {
$ftp->cwd("/FTP/IN") if (!$cwd_performed++)
}

# Put first file to the ftp server
$ftp->put ($2) or
die "$server: cannot put $2: " . $ftp->message;

#Quit FTP when finished
$ftp->quit;

sleep (10 * 60)
}
scheint jetzt richtig zu funktionieren.
habe aber anderes problem mit dem
script, das ich nicht lösen kann.

info file sieht folgerndermassen aus:
----------------------------------
AA1000022 FE000000011

BA1000022 FF0000000012
----------------------------------

zusammen mit info file soll ich jedesmal 2 TEXT files bekommen:
AA1000022 und BA1000022
name von der info datei ändert nie,
aber namen von diesen 2 files, ändern jedesmal.

wie kann man eigentlich zuerst
überprüfen ob die namen von den beiden files
mit den namen im info file übereinstimmen und erst dann,
renamen und per ftp weiterschicken ?

gruss
ccc

SkydiverBS
31.03.2004, 12:26
Hi ccc!

wie kann man eigentlich zuerst
überprüfen ob die namen von den beiden files
mit den namen im info file übereinstimmen und erst dann,
renamen und per ftp weiterschicken ?

Teste doch einfach ob die Dateien die im Info-File angegeben sind existieren oder nicht (mit -e oder -f) und breche das Programm ab falls sie nicht vorhanden sind.

Also z.B. so:

# DO NOT transfer with files missing or with wrong names
-f $old or die "file '$old' is missing\n";


Gruss,
Philip alias Skydiver

ccc
31.03.2004, 12:52
danke !

habe aber noch ein anderes problem
ich kann das 2 file NICHT SCHICKEN,
wenn der erste nicht erfolgreich transferiert wurde.

wie kann ich überprüfen ob der erste file vollständig angekommen ist
und 100% sicher sein dass er dort ist und erst dann das 2 file schicken.
falls der transfer von ersten file nicht klappt, einfach unterbrechen.

gruss
ccc

Jonas
02.04.2004, 10:00
am sichersten wird sein:
File A schicken, anschließend File A nochmal von dem neuen Speicherort runterladen, mit vorhandenem lokalen File vergleichen, und wenn sie übereinstimmen, File B schicken...

ccc
03.04.2004, 11:47
hallo Jonas

danke für den tipp, aber kannst du ein paar zeilen code posten bitte,
wie dies funktionieren sollte.

gruss
ccc