Überprüfen Sie, ob der Ordner Dateien mit Erweiterungen enthält, und schreiben Sie Verzeichnisse in Kategorien

Überprüfen Sie, ob der Ordner Dateien mit Erweiterungen enthält, und schreiben Sie Verzeichnisse in Kategorien

Ich habe über 3.000 Ordner und sie können zwei Dateitypen enthalten, eine einzelne Spring-Datei und ein Paar Fastq.gz-Dateien. Ich möchte die Ordner scannen und wissen, ob beide oder eine der Dateierweiterungen im Verzeichnis vorhanden ist -

  1. Enthält ein Paar fastq.gz- und spring-Dateien
  2. Eine Fastq.gz-Datei und eine Spring-Datei
  3. Eine einzelne Federfeile
  4. Ein Paar fastq.gz-Dateien
  5. Einzelne fastq.gz-Datei

Ich habe es verwendet [ /path/to/dir/*fastq.gz ], aber ich erhalte unary operator expectedeine Fehlermeldung und die Verwendung [[ ]]scheint die Dinge nicht richtig zu testen.

Das eigentliche Skript, das ich verwendet habe, ist -

check_dir () {
in="$1"
echo "$in Checking for spring"
[ "$in"/*spring -f ] && echo "$in"
}
export -f check_dir

Ich verwende Bash, jede Hilfe mit der Logik wird geschätzt

Antwort1

unary operator expectedliegt daran, dass [Sie *(in Ihrem *fastq.gz) selbstständig arbeiten.

[ist keine Shell-Syntax. [ist ein regulärer Befehl (ein eingebauter Befehl in Bash, aber trotzdem ein Befehl) und ]ist sein letzterStreit, ein obligatorisches. Alles dazwischen ist auch ein Argument.

Die Shell erweitert sich /path/to/dir/*fastq.gzzu einem oder mehreren Wörtern, bevor sie aufruft [. [sieht diese Wörter plus die obligatorischen ]als Argumente. Abhängig von der Anzahl der Argumente und davon, um was für Argumente es sich handelt, [werden null oder mehr Argumente als Operatoren erwartet (wie -f).

Ihr [ /path/to/dir/*fastq.gz ]wird gültig sein, wenn /path/to/dir/*fastq.gzes zu einem einzelnen Argument erweitert wird (beachten Sie, dass „wird gültig sein“ nicht gleichbedeutend ist mit „wird tun, was Sie wollen“). Dies schließt Fälle ein, in denen *nichts übereinstimmt; traditionell (und standardmäßig in Bash) /path/to/dir/*fastq.gzwird es so verarbeitet, wie es ist, wenn es keine Übereinstimmung gibt. Es kann vorkommen, dass /path/to/dir/*fastq.gzes zu mehreren Wörtern erweitert wird, von denen keines so aussieht, als würde es ein Operator [verstehen. Der Fehler, den Sie erhalten haben, stammt höchstwahrscheinlich von einem Fall, in dem das Muster zu zwei Wörtern erweitert wurde.

Später haben Sie verwendet [ "$in"/*spring -f ]. Das ist noch schlimmer, weil Sie wahrscheinlich etwas wie „ [ -f some/path ]wo -fistVorder zu testende Pfad. [ -f "$in"/*spring ]Ist immer noch keine robuste Lösung, weil"$in"/*spring Im Algemeinenkann auf mehrere Argumente erweitert werden und [wird diese nicht ertragen. Sie haben geschrieben, dass es höchstens eine *springDatei pro Verzeichnis gibt, alsoin Ihrem FallCode wie dieser funktioniert vielleicht irgendwie, es ist aber trotzdem schlechter Code.

Verwenden Sie bei [keine Platzhalter, *da diese auf mehrere Wörter erweitert werden könnten. Dies schlägt sofort oder bald fehl.[[ist unter der Haube andersaber es ist auch nicht gut für Ihren Zweck.

Sie möchten wissen, mit wie vielen Dateien ein Muster wie dieses /path/to/dir/*fastq.gzübereinstimmt. Der richtige Weg, dies zu tun, besteht darin, das Ergebnis der Erweiterung einem Array zuzuweisen. Portabel gibt es nur ein Array: das Array der Argumente des Shell-Skripts (oder der Shell-Funktion); und Sie benötigen zusätzlichen Code, um einen Fall von null Übereinstimmungen zu erkennen (der immer noch ein Wort generiert: die nicht erweiterte Musterzeichenfolge). Ihre Frage ist markiert, daher werde ich ein benanntes Array und einige andere nicht portable Funktionen verwenden:

# non-portable code, works in Bash
check_dir () (
   dir="${1-.}"
   dir="${dir%/}/"
   [ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
   shopt -s nullglob
   files=( "$dir"/*fastq.gz )
   nf="${#files[@]}"
   files=( "$dir"/*spring )
   ns="${#files[@]}"
   printf '%s\t%s\t%s\n' "$nf" "$ns" "$dir"
)

Verwendung: check_dir path/to/diroder check_dir(der Standardpfad ist .). Die Funktion druckt die Anzahl der *fastq.gzDateien, eine Registerkarte, die Anzahl der *springDateien, eine Registerkarte und schließlich den untersuchten Pfad (gedruckt mit einem abschließenden /).

Jetzt können Sie einen Verzeichnisbaum analysieren (für die folgende Funktion muss die obige Funktion definiert sein):

# non-portable code, works in Bash
check_dirs () (
   dir="${1-.}"
   dir="${dir%/}/"
   [ -d "$dir" ] || { echo "Not a directory." >&2; return 1; }
   shopt -s nullglob globstar
   for d in "$dir"**/; do
      check_dir "$d"
   done
)

Verwendung: check_dirs path/to/diroder check_dirs(der Standardpfad ist .).

Anmerkungen:

  • Bei einem großen Verzeichnisbaum check_dirskann es zunächst zu einem Stocken kommen. Dies liegt daran, dass for d in "$dir"**/er vollständig erweitert werden muss, bevor check_direr überhaupt aufgerufen wird und etwas ausgibt.

  • check_dir () (Die Funktionen sind bewusst als Unter-Shells ( im Gegensatz zu ) definiert check_dir () {, daher sind Shell-Optionen ( shopt) und alle Variablen lokal.

  • Wenn Sie check_dirversteckte Dateien zählen möchten, benötigen Sie dotglobdiese Funktion (also shopt -s nullglob dotglob).

  • Wenn Sie check_dirsin versteckte Verzeichnisse absteigen möchten, benötigen Sie dotglobdiese Funktion (also shopt -s nullglob globstar dotglob).

  • Sofern die Namen Ihrer Verzeichnisse keine Zeilenumbruchzeichen enthalten, kann die Ausgabe von check_diroder check_dirsproblemlos mit Standardtools analysiert werden. Nützliche Befehle: sort -n, grep $'^2\t1\t', cut -f 3-.

    So finden Sie beispielsweise Verzeichnisse ./mit genau einer *fastq.gzDatei und genau null *springDateien:

    check_dirs | grep $'^1\t0\t' | cut -f 3-
    

verwandte Informationen