![Überprüfen Sie, ob der Ordner Dateien mit Erweiterungen enthält, und schreiben Sie Verzeichnisse in Kategorien](https://rvso.com/image/1684200/%C3%9Cberpr%C3%BCfen%20Sie%2C%20ob%20der%20Ordner%20Dateien%20mit%20Erweiterungen%20enth%C3%A4lt%2C%20und%20schreiben%20Sie%20Verzeichnisse%20in%20Kategorien.png)
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 -
- Enthält ein Paar fastq.gz- und spring-Dateien
- Eine Fastq.gz-Datei und eine Spring-Datei
- Eine einzelne Federfeile
- Ein Paar fastq.gz-Dateien
- Einzelne fastq.gz-Datei
Ich habe es verwendet [ /path/to/dir/*fastq.gz ]
, aber ich erhalte unary operator expected
eine 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 expected
liegt 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.gz
zu 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.gz
es 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.gz
wird es so verarbeitet, wie es ist, wenn es keine Übereinstimmung gibt. Es kann vorkommen, dass /path/to/dir/*fastq.gz
es 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 -f
istVorder 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 *spring
Datei 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 markiertSchlag, 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/dir
oder check_dir
(der Standardpfad ist .
). Die Funktion druckt die Anzahl der *fastq.gz
Dateien, eine Registerkarte, die Anzahl der *spring
Dateien, 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/dir
oder check_dirs
(der Standardpfad ist .
).
Anmerkungen:
Bei einem großen Verzeichnisbaum
check_dirs
kann es zunächst zu einem Stocken kommen. Dies liegt daran, dassfor d in "$dir"**/
er vollständig erweitert werden muss, bevorcheck_dir
er überhaupt aufgerufen wird und etwas ausgibt.check_dir () (
Die Funktionen sind bewusst als Unter-Shells ( im Gegensatz zu ) definiertcheck_dir () {
, daher sind Shell-Optionen (shopt
) und alle Variablen lokal.Wenn Sie
check_dir
versteckte Dateien zählen möchten, benötigen Siedotglob
diese Funktion (alsoshopt -s nullglob dotglob
).Wenn Sie
check_dirs
in versteckte Verzeichnisse absteigen möchten, benötigen Siedotglob
diese Funktion (alsoshopt -s nullglob globstar dotglob
).Sofern die Namen Ihrer Verzeichnisse keine Zeilenumbruchzeichen enthalten, kann die Ausgabe von
check_dir
odercheck_dirs
problemlos 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.gz
Datei und genau null*spring
Dateien:check_dirs | grep $'^1\t0\t' | cut -f 3-