Fehler im Skript. Der Befehl „find“ überspringt Ordner mit Leerzeichen

Fehler im Skript. Der Befehl „find“ überspringt Ordner mit Leerzeichen

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- $foound 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 DIRSenthä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 export DIRS=$(…)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.

for d in $DIRS

Und hier verlieren Sie: Sie möchten $DIRSin Wörter aufteilen und können daher keine doppelten Anführungszeichen setzen. Sie benötigen diese jedoch, da $DIRSalle 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 -execOption 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 ."
' {} \;

findBeachten Sie erneut , dass beim Analysieren der Ausgabe im eingebetteten Befehl findIhre 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 findAusgabe 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 echoimmer einen Rückgabewert von 0 hat.

verwandte Informationen