2017-01-25 7 views
4

Der Titel sagt alles. Ich habe es geschafft, nur die Zeilen mit diesem zu bekommen:Die WC-Zeilen an den Dateinamen anhängen

Aber ich könnte eine Hilfe verwenden, die das an den Dateinamen anhängt. Bonuspunkte, um mir zu zeigen, wie man dies über alle .txt-Dateien im aktuellen Verzeichnis durchführt.

+3

Sie sprechen sind die Ausgabe von WC auf das Ende des Namens ein Anheften Datei oder am Ende des Inhalts einer Datei? Bearbeiten Sie Ihre Frage, um eine übersichtliche, testbare Eingabe und erwartete Ausgabe zu erhalten. Ich bin erstaunt, dass du 4 upvotes für eine Frage ohne ein Beispiel hast! Ich habe mehrere Fragen gesehen, wo Leute das Skripttrennzeichen '' s ** in das Skript einfügen ** - ('awk {'foo'}' anstelle von 'awk' {foo} '') - wo zum Teufel ist DAS Idee kommt von ??? –

Antwort

0

Das würde funktionieren, aber es gibt definitiv elegantere Möglichkeiten.

for i in *.txt; do 
    mv "$i" ${i/.txt/}_$(wc $i | awk {'print $1'})_.txt; 
done 

Ergebnis würde die Zeilennummern schön vor dem .txt setzen. Like:

file1_1_.txt 
file2_25_.txt 
+0

Sie sollten eine for-Schleife mit einem Glob machen. Pipe 'ls' nicht – dawg

+0

Edited. Vielen Dank. –

+0

Können Sie mir den Grund dafür erklären? Danke –

0

Rename Befehl

for file in *.txt; do 
lines=$(wc ${file} | awk {'print $1'}); 
rename s/$/${lines}/ ${file} 
done 
0

Sie grep -c '^' verwenden könnte die Anzahl der Zeilen zu bekommen, statt wc und awk:

for file in *.txt; do 
    [[ ! -f $file ]] && continue # skip over entries that are not regular files 
    # 
    # move file.txt to file.txt.N where N is the number of lines in file 
    # 
    # this naming convention has the advantage that if we run the loop again, 
    # we will not reprocess the files which were processed earlier 
    mv "$file" "$file".$(grep -c '^' "$file") 
done 
0
#/bin/bash 

files=$(find . -maxdepth 1 -type f -name '*.txt' -printf '%f\n') 
for file in $files; do 
    lines=$(wc $file | awk {'print $1'}); 
    extension="${file##*.}" 
    filename="${file%.*}" 
    mv "$file" "${filename}${lines}.${extension}" 
done 

Sie können einstellen, Maxdepth entsprechend.

+2

Dies wird abgebrochen, wenn eine der Dateien ein Leerzeichen oder einen Platzhalter in ihnen hat - Worttrennungsfehler. – codeforester

0

Sie können auch wie folgt tun:

for file in "path_to_file"/'your_filename_pattern' 
    do 
     lines=$(wc $file | awk {'print $1'}) 
     mv $file $file'_'$lines 
    done 

Beispiel:

for file in /oradata/SCRIPTS_EL/text* 
    do 
     lines=$(wc $file | awk {'print $1'}) 
     mv $file $file'_'$lines 
    done 
5
find -name '*.txt' -execdir bash -c \ 
    'mv -v "$0" "${0%.txt}_$(wc -l < "$0").txt"' {} \; 

wo

  • der bash Befehl für jede (\;) angepasst Datei ausgeführt wird ;
  • {} wird durch den aktuell verarbeiteten Dateinamen ersetzt und als erstes Argument ($0) an das Skript übergeben;
  • ${0%.txt} löscht kürzeste Übereinstimmung von .txt von der Rückseite der Zeichenfolge (siehe official Bash-scripting guide);
  • wc -l < "$0" druckt nur die Anzahl der Zeilen in der Datei (siehe Antworten auf this question, zum Beispiel)

Beispielausgabe:

'./file-a.txt' -> 'file-a_5.txt' 
'./file with spaces.txt' -> 'file with spaces_8.txt' 
+0

Professionelles Aussehen und Gefühl. Auch nur eine, die 'wc -l' verwendet. ++ –

+1

Sie sollten '$ (Basisname" $ ​​0 ".txt)' durch '$ {0% .txt}' ersetzen: 'Basisname' ist in diesem Fall definitiv nutzlos und ineffizient! und vielleicht auch "-type f" in den 'find' Prädikaten. –

+0

@ gniourf_gniourf, tatsächlich. Vielen Dank. –

0
awk ' 
    BEGIN{ for (i=1;i<ARGC;i++) Files[ARGV[i]]=0 } 

    {Files[FILENAME]++} 

    END{for (file in Files) { 
     # if(file !~ "_" Files[file] ".txt$") { 

      fileF=file;gsub(/\047/, "\047\"\047\"\047", fileF) 
      fileT=fileF;sub(/.txt$/, "_" Files[file] ".txt", fileT) 

      system(sprintf("mv \047%s\047 \047%s\047", fileF, fileT)) 

     # } 
     } 
    }' *.txt 

Eine weitere Möglichkeit, mit awk einfacher, eine zweite zu verwalten Schleife, indem man mehr Kontrolle über den Namen erlaubt (wie man vermeidet, dass man bereits die Zählung innerhalb des vorherigen Zyklus hat)

Wegen Schmiere d Bemerkung von @gniourf_gniourf:

  • Dateinamen mit Raum im Inneren möglich
  • winzige Code ist jetzt schwer für eine so kleine Aufgabe
+0

Schlechtes Design von Anfang an: Sie mischen Code und Daten! Was ist, wenn ein Dateiname ein Zitat enthält? –

+0

Sie haben Recht, ich vergesse das anzunehmen. Es gibt ein zweites Problem, leere Dateien, die nie erreichen (mit ARGV lösen Sie das, aber erstellen Sie ein Problem mit spacy Namen, ...) versuchen Sie mehrere Tipps, aber es erstellen eine Gaz-Fabrik (modular, aber unzulänglich für so kleine Anfrage). Ich habe die letzte Version mit Annahme übernommen, bis besser – NeronLeVelu

+0

angepasster Code für Leerzeichen und einfaches Anführungszeichen innerhalb des Dateinamens – NeronLeVelu

0
{ linecount[FILENAME] = FNR } 
END { 
    linecount[FILENAME] = FNR 
    for (file in linecount) { 
     newname = gensub(/\.[^\.]*$/, "-"linecount[file]"&", 1, file) 
     q = "'"; qq = "'\"'\"'"; gsub(q, qq, newname) 
     print "mv -i -v '" gensub(q, qq, "g", file) "' '" newname "'" 
    } 
    close(c) 
} 

Speichern Sie die oben awk Skript in einer Datei, sagen wcmv.awk, wie der Lauf es:

awk -f wcmv.awk *.txt 

es wil Ich listet die Befehle auf, die ausgeführt werden müssen, um die Dateien in der erforderlichen Weise umzubenennen (außer dass leere Dateien ignoriert werden). Um sie tatsächlich auszuführen, können Sie die Ausgabe wie folgt zur Ausgabe an eine Shell übergeben.

Wie bei allen irreversiblen Batch-Operationen, seien Sie vorsichtig und führen Sie Befehle nur aus, wenn sie in Ordnung sind.

+0

Schlechtes Design von Anfang an: Sie mischen Code und Daten _ was ist, wenn ein Dateiname ein Zitat enthält? –

+0

@gniourf_gniourf Ich denke, einfache Anführungszeichen in Dateinamen werden jetzt keine Probleme verursachen. Und nun, dieser Code sieht jetzt wehleidig aus. : P –

1

Sie könnten den rename Befehl verwenden, die eigentlich ein Perl-Skript ist, wie folgt:

rename --dry-run 'my $fn=$_; open my $fh,"<$_"; while(<$fh>){}; $_=$fn; s/.txt$/-$..txt/' *txt 

Beispielausgabe

'tight_layout1.txt' would be renamed to 'tight_layout1-519.txt' 
'tight_layout2.txt' would be renamed to 'tight_layout2-1122.txt' 
'tight_layout3.txt' would be renamed to 'tight_layout3-921.txt' 
'tight_layout4.txt' would be renamed to 'tight_layout4-1122.txt' 

Wenn Sie mögen, was sie sagt, entfernen Sie die --dry-run und führe es nochmals aus.

Das Skript zählt die Zeilen in der Datei ohne Verwendung von externen Prozessen und benennt sie dann wie Sie fragen, auch ohne Verwendung externer Prozesse, also ziemlich effizient.

Oder, wenn Sie glücklich sind, einen externen Prozess aufzurufen, um die Linien zu zählen, und vermeiden Sie das Perl-Methode oben:

rename --dry-run 's/\.txt$/-`grep -ch "^" "$_"` . ".txt"/e' *txt 
+1

Das Problem mit 'rename' ist, dass es in vielen Varianten erscheint. Die Version, die mit Perl geliefert wird, ist praktisch, andere sind weniger leistungsfähig. – hek2mgl

+1

@ hek2mgl ist richtig. Zum Beispiel kommt 'rename' in meinem Gentoo-Setup von' sys-apps/util-linux'-Paket (https://www.kernel.org/pub/linux/utils/util-linux/), und das tut es nicht unterstütze Perl leider. Und die Perl-Version wird von 'dev-perl/rename' als' perl-rename' ausführbar zur Verfügung gestellt. –