2016-07-19 19 views
0

Ich eingebettet ein Perl Einzeiler in einem Perl-Skript, dessen Zweck ist in-Stelle ersetzt eine Zeichenfolge durch eine andere für jede Zeile der Dateien mit der Namenserweiterung .ini, aber Ich habe festgestellt, dass jede Datei mit .bak gesichert wird.Verwenden von Perl Einzeiler in Perl-Skript

Da im One-Liner, ich nur -i statt -i.bak angeben, frage ich mich, warum die .bak-Datei generiert werden könnte.

foreach my $dir (glob "*.ini") { 
    system qq(perl -i -pe 's|Default|UTF-8|' $dir);   
} 

Eine andere Frage ist, ob es eine bessere, prägnante Perl-Skript das gleiche Ziel (ohne BAK-Datei gesichert werden sollen) zu erreichen, unabhängig von Einzeiler oder nicht.

+0

Arbeiten Sie auf einem Windows-System? – Borodin

+0

@Borodin, ja, alles unerwartet in Windows? – Zii

+0

Sie können unter Windows nicht direkt bearbeiten. Siehe meine Antwort unten. – Borodin

Antwort

1

Hier ist eine Möglichkeit, ohne eine andere Instanz von Perl Shell-out. Diese Technik verwendet eine Zwischen temporäre Datei:

use warnings; 
use strict; 

for my $file (glob "*.ini") { 
    open my $fh, '<', $file or die $!; 
    open my $wfh, '>', 'temp.txt' or die $!; 

    while (<$fh>){ 
     s/Default/UTF-8/; 
     print $wfh $_; 
    } 
    close $fh; 
    close $wfh; 
    unlink $file or die $!; 
    rename 'temp.txt', $file; 
} 

Verwenden Sie diese Version, wenn Sie wissen, dass Ihre Dateien sind nicht übermäßig groß. Er liest die gesamte Datei in dem Speicher (ein einzelner Zeichenfolge Skalar) und erfordert nicht die Vermittler temporäre Datei:

use warnings; 
use strict; 

for my $file (glob "*.ini") { 
    open my $fh, '<', $file or die $!; 

    my $contents; 
    { 
     local $/; 
     $contents = <$fh>; 
    } 
    close $fh; 

    $contents =~ s/Default/UTF-8/; 

    open my $wfh, '>', $file or die $!; 
    print $wfh $contents; 
    close $wfh; 
} 
+0

Das 'rename' in Ihrem ersten Beispiel schlägt fehl, weil die ursprüngliche Datei mit diesem Namen noch existiert. – Borodin

+0

es fällt mir nicht auf Linux Mint. Meinst du auf Windows? – stevieb

+0

Ja. Wir haben festgestellt, dass das OP ein Windows-System ausführt. – Borodin

2

Ich denke, dass Sie bei einigen alten Datendateien suchen. Soweit ich weiß, wird Perl unter keinen Umständen eine Standarddateierweiterung von .bak annehmen

Wenn Sie die Option als nur -i angeben, dann wird versucht, die Datei in-Ort zu bearbeiten, indem Sie die Eingabedatei danach löschen wurde geöffnet und erstellt eine neue Ausgabedatei mit demselben Namen. Die alte Datei lesbar bleibt, bis es geschlossen ist

Diese Technik unter Windows nicht funktioniert, und so ist es ein Fehler mit einer nackten -i Option auf dieser Plattform Es

zu verwenden, besteht keine Notwendigkeit, eine zu berappen 2. Perl-Prozess nur um einige Dateien zu bearbeiten. Es kann sehr einfach so gemacht werden. Die interne Variable $^I entspricht dem Wert der Option -i in der Befehlszeile. Noch einmal, wenn Sie auf einem Windows-System arbeiten dann $^I kann keine leere Zeichenfolge sein und Sie werden es zu .bak oder etwas ähnliches

{ 
    local @ARGV = glob 'f.*'; 
    local $^I = ''; # Must be non-blank on Windows 

    while (<>) { 
     s/Default/UTF-8/g; 
     print; 
    } 
} 
+0

Ich mag dieses, weil es ziemlich prägnant ist. Gibt es eine Quelle, auf die ich verweisen kann, wenn Sie sagen, dass diese Technik unter Windows nicht funktioniert? – Zii

0

Ich denke, find bash Befehl + xargs und Perl einstellen müssen, sollten einfacher sein als Perl-Schleife.

find . -name '*.ini' |xargs perl -pi -e 's/Default/UTF-8/g' 
1

perl -i läuft auf den folgenden Kern nach unten:

open(my $fh_in, '<', $qfn); 
unlink($qfn); 
open(my $fh_out, '>', $qfn); 

$fh_in ist ein anonyme Datei-Handle genannt. Beachten Sie, dass die zugehörige Datei, aus der sie gelesen wurde, nicht mehr im Verzeichnis vorhanden ist.

Das Problem ist, dass Windows keine anonymen Dateizugriffsnummern unterstützt. Wenn Sie eine Datei löschen, die bereits geöffnet ist, bleibt der Verzeichniseintrag bestehen, bis die Datei geschlossen wird. Dies verhindert, dass Perl eine Ausgabedatei mit demselben Namen erstellt. Aus diesem Grund wird -i (ohne Erweiterung) unter Windows nicht unterstützt.

>perl -i -ne"..." file 
Can't do inplace edit without backup. 

Aber Sie verwenden nicht Windows. Sie verwenden Cygwin, eine Umgebung, die Unix emuliert. Aus diesem Grund hat die Verwendung von -i (ohne Erweiterung) keinen Fehler ergeben.Cygwin ist jedoch immer noch auf die Fähigkeiten des Host-Betriebssystems beschränkt, so dass keine anonymen Dateien erstellt werden können [1]. Daher ist Perl so programmiert, als ob -i.bak bereitgestellt würde, wenn -i für einen Cygwin-Build von Perl bereitgestellt wird.


  1. Es scheint, sie emulieren zu können, aber das Merkmal aus irgendeinem Grund wird nicht verwendet.

    $ cat foo 
    abc 
    def 
    
    $ perl -E' 
        open(my $fh, "<", "foo") or die $!; 
        system("ls -1"); 
        say "--"; 
        unlink("foo") or warn $!; 
        system("ls -1"); 
        say "--"; 
        print while <$fh>; 
    ' 
    foo 
    -- 
    -- 
    abc 
    def 
    
+0

WOW, das ist die richtige Antwort! – Zii

Verwandte Themen