Ich brauche ein Skript, das die Dateien in einem Verzeichnis (und Unterverzeichnis) zählt. Ich habe das folgende Skript genommen und es meinen Bedürfnissen entsprechend geändert.
Es funktioniert wie es soll, außer bei Ordnern mit Leerzeichen. Ich bin ziemlich sicher, dass mir irgendwo Anführungszeichen fehlen, aber ich kann es noch nicht herausfinden.
Weitere Informationen
- Linux 2.6.22.19-0.4-default (dieser Server befindet sich nicht mehr in einer produktiven Umgebung.)
- GNU Find Version 4.2.31
- Ich kann die Verzeichnisse nicht umbenennen.
Beispiel einer Verzeichnisstruktur
.
..
01_infos
02_sent
03_inbox
04_public and private
197.
145.
329.
13.
Skript
#!/bin/bash
# Write a script that will count the number of files in each of your subdirectories.
# -------------------------------------------------------------------------
# Copyright (c) 2001 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
START=$HOME
# change your directory to command line if passed
# otherwise use home directory
[ $# -eq 1 ] && START=$1 || :
if [ ! -d $START ]
then
echo "$START not a directory!"
exit 1
fi
# use find command to get all subdirs name in DIRS variable
DIRS=$(find "$START" -type d)
# loop thought each dir to get the number of files in each of subdir
for d in $DIRS
do
echo "$d directory has $(find "$d" -maxdepth 1 -regex '.*\.' -type f | wc -l) files" || :
done
Ausgabe
./01_infos directory has 1 files
./02_sent directory has 9 files
./03_inbox has 4 files
find: ./04_public: No such file or directory
Antwort1
Ihnen fehlen einige doppelte Anführungszeichen (Setzen Sie Variablen- $foo
und Befehlssubstitutionen immer in Anführungszeichen$(foo)
, es sei denn, Sie wissen, warum Sie sie getrost weglassen können und müssen). Aber das ist nicht das ganze Problem.
if [ ! -d $START ]
sollte sein if [ ! -d "$START" ]
.
DIRS=$(find "$START" -type d)
An dieser Stelle DIRS
enthält rekursiv den Namen des Startverzeichnisses und seiner Unterverzeichnisse, mit Zeilenumbrüchen dazwischen. Wenn Sie also einen Verzeichnisnamen haben, der einen Zeilenumbruch enthält, haben Sie verloren: Es ist unmöglich zu wissen, welche Zeilenumbrüche aus einem Verzeichnisnamen stammen und welche Trennzeichen waren. Wenn Sie wissen, dass Dateinamen keine Zeilenumbrüche enthalten, können Sie die Ausgabe von analysieren find
, aber woher sollen Sie das wissen?
Übrigens ist es in Ordnung, hier keine Anführungszeichen zu verwenden, $(…)
da es sich um eine Variablenzuweisung handelt und Ersetzungen in Zuweisungen implizit geschützt sind. Beachten Sie jedoch, dass dies nicht in gleicher Weise geschützt ist. Verwenden Sie am besten Anführungszeichen, es sei denn, Sie beherrschen Shell-Skripting und alle Personen, die Ihr Skript pflegen, sind ebenfalls mit diesen vertraut.export DIRS=$(…)
for d in $DIRS
Und hier verlieren Sie: Sie möchten $DIRS
in Wörter aufteilen und können daher keine doppelten Anführungszeichen setzen. Sie benötigen diese jedoch, da $DIRS
alle Elemente miteinander verkettet sind und die Dateinamen in den Leerzeichen als Trennzeichen dienen würden, wenn Sie sie nicht in Anführungszeichen setzen.
Wenn Sie verwenden find
, sollten Sie normalerweise dafür sorgen, dass der Verarbeitungsbefehl mit der -exec
Option aufgerufen wird. Sofern Sie die Dateinamen nicht streng kontrollieren, sollten Sie die Ausgabe von nicht analysieren find
: Sie ist mehrdeutig.
find "$START" -type d -exec sh -c '
echo "$0 directory has $(find "$0" -maxdepth 1 -regex ".*\\." -type f -printf \\n | wc -l) files whose name ends with ."
' {} \;
find
Beachten Sie erneut , dass beim Analysieren der Ausgabe im eingebetteten Befehl find
Ihre Zählung falsch ist, wenn ein beliebiger Dateiname eine neue Zeile enthält.
Antwort2
Wie wäre es nur damit?
find . -type d -exec sh -c '/bin/echo -n "{}"; find "{}" -maxdepth 1 -regex ".*\." -type f | wc -l; ' \;
Die Ausgabe ist nicht ganz so zuckersüß, erfordert aber kein Skript und funktioniert für Verzeichnisse mit Leerzeichen sowie anderen nicht alphanumerischen Zeichen.
Antwort3
Sie haben einen klassischen Zitierfehler. Korrigieren Sie die For-Schleife so, dass sie wie folgt aussieht:
for d in "$DIRS"
Alternativ können Sie die find
Ausgabe auch direkt einspeisen, zB:
find "$START" -type d | while read d
do # and so on...
Abgesehen davon || :
ist das Bit völlig redundant, da es echo
immer einen Rückgabewert von 0 hat.