Ich möchte alle Unterordner finden, die eine Markdown-Datei mit demselben Namen (und derselben Erweiterung .md
) enthalten.
Zum Beispiel: Ich möchte folgende Unterordner suchen:
Apple/Banana/Orange #Apple/Banana/Orange/Orange.md exists
Apple/Banana #Apple/Banana/Banana.md exists
Apple/Banana/Papaya #Apple/Banana/Papaya/Papaya.md exists
- Hinweis: Das Verzeichnis kann andere Dateien oder Unterverzeichnisse enthalten.
Irgendwelche Vorschläge?
Die Lösungen für das Problem können mit dem folgenden Code getestet werden:
#!/usr/bin/env bash
# - goal: "Test"
# - author: Nikhil Agarwal
# - date: Wednesday, August 07, 2019
# - status: P T' (P: Prototyping, T: Tested)
# - usage: ./Test.sh
# - include:
# 1.
# - refer:
# 1. [directory - Find only those folders that contain a File with the same name as the Folder - Unix & Linux Stack Exchange](/unix/534190/find-only-those-folders-that-contain-a-file-with-the-same-name-as-the-folder)
# - formatting:
# shellcheck disable=
#clear
main() {
TestData
ExpectedOutput
TestFunction "${1:?"Please enter a test number, as the first argument, to be executed!"}"
}
TestFunction() {
echo "Test Function"
echo "============="
"Test${1}"
echo ""
}
Test1() {
echo "Description: Thor"
find . -type f -regextype egrep -regex '.*/([^/]+)/\1\.md$' | sort
echo "Observation: ${Green:=}Pass, but shows filepath instead of directory path${Normal:=}"
}
Test2() {
echo "Description: Kusalananda1"
find . -type d -exec sh -c '
dirpath=$1
set -- "$dirpath"/*.md
[ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]' sh {} \; -print | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test3() {
echo "Description: Kusalananda2"
find . -type d -exec sh -c '
for dirpath do
set -- "$dirpath"/*.md
if [ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]
then
printf "%s\n" "$dirpath"
fi
done' sh {} + | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test4() {
echo "Description: steeldriver1"
find . -type d -exec sh -c '[ -f "$1/${1##*/}.md" ]' find-sh {} \; -print | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test5() {
echo "Description: steeldriver2"
find . -type d -exec sh -c '
for d do
[ -f "$d/${d##*/}.md" ] && printf "%s\n" "$d"
done' find-sh {} + | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test6() {
echo "Description: Stéphane Chazelas"
find . -name '*.md' -print0 \
| gawk -v RS='\0' -F/ -v OFS=/ '
{filename = $NF; NF--
if ($(NF)".md" == filename) include[$0]
else exclude[$0]
}
END {for (i in include) if (!(i in exclude)) print i}'
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test7() {
echo "Description: Zach"
#shellcheck disable=2044
for fd in $(find . -type d); do
dir=${fd##*/}
if [ -f "${fd}/${dir}.md" ]; then
ls "${fd}/${dir}.md"
fi
done
echo "Observation: ${Green:=}Pass but shows filepath instead of directory${Normal:=}"
}
ExpectedOutput() {
echo "Expected Output"
echo "==============="
cat << EOT
./GeneratedTest/A
./GeneratedTest/A/AA
./GeneratedTest/B
./GeneratedTest/C/CC1
./GeneratedTest/C/CC2
EOT
}
TestData() {
rm -rf GeneratedTest
mkdir -p GeneratedTest/A/AA
touch GeneratedTest/index.md
touch GeneratedTest/A/A.md
touch GeneratedTest/A/AA/AA.md
mkdir -p GeneratedTest/B
touch GeneratedTest/B/B.md
touch GeneratedTest/B/index.md
mkdir -p GeneratedTest/C/CC1
touch GeneratedTest/C/index.md
touch GeneratedTest/C/CC1/CC1.md
mkdir -p GeneratedTest/C/CC2
touch GeneratedTest/C/CC2/CC2.md
mkdir -p GeneratedTest/C/CC3
touch GeneratedTest/C/CC3/CC.md
mkdir -p GeneratedTest/C/CC4
}
main "$@"
foo/foo.md
oderfoo/bar.md
solltenfoo
eingeschlossen oder ausgeschlossen werden?-printf
mit find verwenden, können Sie jeden Teil des Spiels erhalten, den Sie wollen, siehe meine BearbeitungAntworten:
Vorausgesetzt, Ihre Dateien haben einen vernünftigen Namen, dh keine Notwendigkeit
-print0
usw. Sie können dies mit GNU find folgendermaßen tun:Ausgabe:
Wenn Sie nur den Verzeichnisnamen möchten, fügen Sie ein
-printf
Argument hinzu:Ausgabe bei Ausführung mit Ihren aktualisierten Testdaten:
quelle
find . -type f | egrep '.*/([^/]+)/\1\.md$'
print0
.%h
in printf wird für den zu formatierenden Datentyp int verwendet. Referenz: printf Format String - Wikipedia . Könnten Sie bitte diesen Teil erklären? Wie wird%h
hier verwendet?find
, siehe Abschnitt 3.2.2.1 im Handbuch für weitere Details.Auf einem GNU-System können Sie Folgendes tun:
quelle
zsh
Lösung (ich glaube, sie hat zwei der positiven Stimmen erhalten) und weisen Sie auf Mängel hin, die Sie möglicherweise dazu veranlasst haben, sie zu entfernen.Das Obige würde alle Verzeichnisse unterhalb des aktuellen Verzeichnisses (einschließlich des aktuellen Verzeichnisses) finden und für jedes ein kurzes Shell-Skript ausführen.
Der Shell-Code würde testen, ob es eine Markdown-Datei mit demselben Namen wie das Verzeichnis im Verzeichnis gibt und ob dies der einzige
*.md
Name in diesem Verzeichnis ist. Wenn eine solche Datei vorhanden ist und dies der einzige*.md
Name ist, wird das Inline-Shell-Skript mit einem Exit-Status von Null beendet. Andernfalls wird es mit einem Exit-Status ungleich Null beendet (Signalisierungsfehler).Das
set -- "$dirpath"/*.md
Bit setzt die Positionsparameter auf die Liste der Pfadnamen, die dem Muster entsprechen (entspricht jedem Namen mit einem Suffix.md
im Verzeichnis). Wir können dann$#
später verwenden, um zu sehen, wie viele Übereinstimmungen wir daraus erhalten haben.Wenn das Shell-Skript erfolgreich beendet wird,
-print
wird der Pfad zum gefundenen Verzeichnis gedruckt.Etwas schnellere Version, die weniger Aufrufe des Inline-Skripts verwendet, aber nicht mehr mit den gefundenen Pfadnamen
find
selbst tun kann (das Inline-Skript kann jedoch weiter erweitert werden):Dieselben Befehle, ohne sich darum zu kümmern, ob sich andere
.md
Dateien in den Verzeichnissen befinden:Siehe auch:
quelle
Entweder
oder
Um zu vermeiden, dass eine
sh
pro Datei ausgeführt wird.Dies
find-sh
ist eine willkürliche Zeichenfolge, die zum nullten Positionsparameter der Shell wird. Wenn$0
Sie etwas Fehlerhaftes feststellen, kann dies beim Debuggen hilfreich sein, falls die Shell auf Fehler stößt (andere empfehlen möglicherweise die Verwendung von Plainsh
oder sogar_
als Standardparameter "Überspringen").quelle
Hier ist meins. Ich habe weitere Verzeichnisse und Dateien hinzugefügt, um dies zu überprüfen. Ich war auch gelangweilt, also habe ich die letzte geänderte Zeit und MD5 hinzugefügt. Vielleicht suchen Sie nach Duplikaten.
quelle
Dies würde ein wenig Logik erfordern.
Sie können dies auch mithilfe von Codeblöcken so anpassen, dass es in einen Einzeiler passt.
EDIT: Bash ist schwer.
basedir
ist kein Befehl,dirname
macht nicht das, was ich dachte, also lass uns mit der Parametererweiterung fortfahren.quelle
dirname
ist der Befehl, nach dem Sie suchen, und Zuweisungen dürfen keine Leerzeichen um das enthalten=
.