Bash: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen
-
DU hast nach dem Use Case gefragt.
Na ja, aber es funktioniert ja ... Nur halt abgehackt.
-
@ShredderButtonOn mich stört der Dialog nicht, ich sagte nur, dass du mit deinem One-Liner einfach nur ein bisschen Chaos anrichtest und man nicht nachvollziehen kann was du eigentlich tun willst.
-
Auch wenn das sicher eine interessante Herausforderung für die Kommandozeilenmittel wäre, besonders als Einzeiler, ist komplexe Zeichenkettenmanipulation wohl ein Fall, wo man besser eine höhere Scriptsprache wählen sollte. Besonders das Transponieren wird sonst ekelig. In Python oder ähnlichen Sprachen wären das bloß wenige, kurze, einfach verständliche Zeilen.
Man kann das ja sogar einfach kombinieren und die Handhabe der Ordnernamen mit den Kommandozeilen machen (Denn dafür sind die ideal!) und diese dann an das Script zur Ausgabe übergeben.
-
@SeppJ tut mir Leid aber ich verstehe nicht was du meinst.
Die Zeile ist eigentlich ein totaler Bullshit und das sollte man so nicht machen,
-
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Die Zeile ist eigentlich ein totaler Bullshit
Eh, nein?
-
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Die Zeile ist eigentlich ein totaler Bullshit
Eh, nein?
Das
xargs
an deinem Ende, ist das, was mich irritiert.
-
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Die Zeile ist eigentlich ein totaler Bullshit
Eh, nein?
Das
xargs
an deinem Ende, ist das, was mich irritiert.Dafür könnte man auch
column
verwenden ... aber das funktioniert wie gesagt nicht ganz
-
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
@SeppJ tut mir Leid aber ich verstehe nicht was du meinst.
Du kannst 150 Minuten daran feilen, das optimal mit den GNU Core Utilities als Einzeiler zu basteln, bis das zuverlässig und mit allen erdenklichen Sonderfällen funktioniert. Und das Ergebnis würde den wenigen Leuten, die das lesen können, die Tränen kommen lassen vor lauter Schönheit, dass jemand so etwas geschaffen hat.
Oder du kannst das in 15 Minuten in einer "richtigen" Programmiersprache deiner Wahl machen, und es würde nicht einmal einen Eintrag als Übungsaufgabe in einem Lehrbuch wert sein, weil zu einfach.
Optimalerweise aber eine Kombination aus beidem, denn
find . -mindepth 1 -maxdepth 1 -type d
will man dann doch nicht neu erfinden, in egal welcher Sprache.
-
@SeppJ das sind wahrhaft weise und werte Worte die du für deinen Beitrag gewählt hast
@SeppJ sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Oder du kannst das in 15 Minuten in einer "richtigen" Programmiersprache deiner Wahl machen, und es würde nicht einmal einen Eintrag als Übungsaufgabe in einem Lehrbuch wert sein, weil zu einfach.
Dem stimme ich nicht zu. Ja, Bash ist komplett die falsche Sprache um solche Sachen zu bewerkstelligen und andere Sprachen haben wenigstens die nötigen Bordmittel um sowas umzusetzen.
Das, was @ShredderButtonOn versucht zu "kippen" sieht für mich fast aus, wie Vectoring (aus der Mathe, kann mich irren) und mit Bash kannst du da auch nicht viel anfangen.
Das bedeutet aber nicht, dass ich schlecht in irgendwelcher Programmiersprache bin, weil ich ein Array nicht umgedreht kriege, weil ich von Mathe nicht viel verstehe.
Und ich kann immer und immer wieder betonen, dass der One-Liner nicht gut ist. Und Schadcode ist.EDIT: Solange du bei dem
xargs
Kommando kein initiales Kommando angibst, wird kein zusammengetrimmter Bullshit ausgeführt, sondern agiert wieecho
. Also doch kein Schadcode.Du Herangehensweise finde ich trotz allem immer noch ziemlich umstritten.Das, was @wob sagte.
ls -d */
und überhauptls
soll man in Bash Scripts nie verwenden. Es sei denn du benutzt das Flag-1
noch dazu, das gibt dir jeden Ordner einzig und allein in einer Zeile. Daraus kannst du ein Array erzeugen und es dir anschaulich machen wie du willst. Und es geht noch besser: Dasls
brauchst du überhaupt nicht. Mit diesem One-Liner:printf '%s %s %s %s %s\n' */
listest du jeden Ordner in einer 5-Kolonnnen-Struktur.
-
Ich habe jetzt schon das nächste Problem.
find prefix* -mindepth 3 -name '*.ending' | xargs -I {} mv -v {} ..
Ich möchte, alle Dateien mit Endung .ending, die in der dritten Ebene liegen, eine Ebene weiter nach oben verschieben, ausgehend vom jeweiligen Dateiverzeichnis.
Beispiel
pwd = .
Datei 1 = ./a/b/c/x.ending
Datei 1 nach Verschiebung = ./a/b/x.ending
Datei 2 = ./d/b/c/x.ending
Datei 2 nach Verschiebung = ./d/b/x.endingProblem
Das
..
bezieht sich aber immer auf dasaktuellebasis wd (also.
) ...Hat jemand vielleicht eine Idee? Datei 1 und 2 können nicht absolut/voll adressiert werden, da die "Unterverzeichnisstruktur" ja bei jeder Datei unterschiedlich ist.
Nach einer kurzen Suche auf StackO wurde ich (noch) nicht fündig.
-
Du könntest
dirname
auf den Dateinamen anwenden, dann wieder/..
anhängen. Gibt bestimmt auch irgendwelche anderen tollen Tricks mit%
, aber die Syntax dafür ist mir zu fummelig. Ungefähr so sollte das gehen:find prefix* -mindepth 3 -name '*.ending' -exec bash -c 'mv "{}" $(dirname "{}")/..' \;
Und jetzt möge @siri bitte kommen und genau erklären, was ich hier wo warum wie gequotet habe. Und wieso ich
-exec
genommen habe, und wieso ich darin einbash -c
mache, anstatt dasmv
direkt imexec
zu machen. Laut siris Aussagen im Thread Bash vs. Powershell sind Bash-Quotingregeln schließlich ganz einfach.
-
@siri sagte in [BASH: Tabelle mit 5 Spalten aus
Das, was @wob sagte.
ls -d */
und überhauptls
soll man in Bash Scripts nie verwenden.Genau das hat wob ja gerade nicht vorgeschlagen. Lesen! Verstehen!
-
@SeppJ Danke!
-
@SeppJ muss ich dir jetzt etwas beweisen?
Man soll eh kein
bash -c
in einemfind
machen. Warum wollt ihr auch eigentlich immer alles in eine einzige Zeile quetschen? Durch bestimmtes Quoting, indem du versuchst Bash-Ausdrücke in deinem-c
Switch anzugeben wird das Argument zum ersetzen nicht vonfind
übernommen, was daraus resultiert, dass auch genau der String{}
als Argument verwendet wird.Man kanns sich halt auch einfacher machen. Du kannst dir eine Liste an Dateinamen erzeugen und einfach darüber iterieren, das ist dann zwar kein One-Liner mehr, jedoch viel übersichtlicher:
mapfile -t files < <(find "$1" -maxdepth 3 -name '*.ending') for file in "${files[@]}"; do echo "${file}" "$(dirname "${file}")/.." # echo "${file}" "${file%/*}/.." done
Du hast in deiner
find
Expression übrigens das Quoting rundherum$(...)
vergessen. Und wie gesagt,bash -c
sollte man beifind
nicht machen.Bemerke auch das
mapfile
das ich verwendet habe, um ein Line-basiertes Array zu erstellen und ein Bash-internes Kommando ist und man solche Ausdrücke wiefiles=("$(find ...)")
vermeiden soll.Was das Quoting angeht, kannst du diese einfach verschachteln, so wie in meinem Beispiel
"$(dirname "${file}")/.."
. Viel mehr ist es nicht.EDIT: Außerdem würde ich hier auch kein
dirname
verwenden, sondern"${file%/*}/.."
. Das wäre noch pfiffiger und du ersparst dir obendrein noch einen Prozess.
-
Aber ... tief durchschnauf, das wäre doch jetzt ein Fall, in dem ein Bash-One-Liner nicht das beste Werkzeug für den Use-Case wäre. Ich stimme da dem SeppJ zu, und siri nur teilweise.
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Außerdem würde ich hier auch kein dirname verwenden, sondern "${file%/*}/..".
Wer soll denn das noch a) lesen können, b) lernen und c) gut finden ... das geht langsam in Richtung Kryptografie und Esoterik. Außerdem: Ist es robust? Also dürfen auch Leerzeichen usw. im Pfad vorkommen? Gibt es Edge-Cases?
-
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Wer soll denn das noch a) lesen können, b) lernen und c) gut finden
@ShredderButtonOn ja was hast du denn jetzt lieber, verschachtelte Quotes oder ein bisschen Syntax-Zucker mit nur einem normalen Quote?
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Außerdem: Ist es robust?
Robust genug. Wenn du saubere Scripts schreibst, ist es immer sicher. Es gibt ein Makel, und zwar, dass der Dateinamen nicht mit einem
/
enden darf, was vielleicht eine valide Filesystem-Referenz wäre, aber zeigt, dass kein Code von Redundanz geplagt ist.@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Also dürfen auch Leerzeichen usw. im Pfad vorkommen?
Ja
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Gibt es Edge-Cases?
ja. Wenn dein Dateiname mit
/
endet, was von Redundanz zeugt, und eh nicht vorkommen dürfte. Deshalb soll man aufpassen, dass, wenn du hard-kodierte Dateipfäde in String-Variablen definierst, dass diese auch wenigstens sauber hard-kodiert, sind, alsofp=/home/shredder/f.txt
und nichtfp=/home/shredder/f.txt/
.
-
@siri sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
ja was hast du denn jetzt lieber, verschachtelte Quotes oder ein bisschen Syntax-Zucker mit nur einem normalen Quote?
Eine Indirektion weniger, ist immer besser ... dennoch finde ich das fast unübersichtlich ... aber das soll keine Kritik an dir sein, eher ein subjektives Empfinden.
-
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
aber das soll keine Kritik an dir sein, eher ein subjektives Empfinden.
Darin kritisierst du halt nicht mich, sondern Bash. Parameter expansion ist sauberer und um ein vielfaches schneller.
-
Hm, und was sagen die übrigen dazu?
-
@ShredderButtonOn sagte in BASH: Tabelle mit 5 Spalten aus Ordnernamen in einem Ordner erstellen:
Hm, und was sagen die übrigen dazu?
Parameterexpansion ist schon eine feine Sache, wenn man nur Effizienz betrachtet. Aber hat halt auch unerwartete Nachteile.
Hier musste siri einige Verrenkungen machen, um es überhaupt nutzen zu können. Ist das noch effizient? Wahrscheinlich sogar ja, weil die Subprozesse und Pipes, die man dadurch spart, ganz schön teuer sind. Aber dann muss man wieder fragen, wen in so einem Anwendungsfall Effizienz im Mikrosekundenbereich interessiert.
Ein weiterer, nicht offensichtlicher Nachteil ist, dass das manchmal auf unerwartete Art fehlschlagen kann. Das hier gezeigte
${file%/*}
funktioniert hier nur, weil die Ergebnisse vonfind
garantiert die richtige Form dafür haben. Wenn aberfile=test.txt
wäre (was ja ganz legitim ist, wenn test.txt im aktuellen Verzeichnis liegt), dann würde${file%/*}
zu nix expandiert, wohingegendirname $file
immer noch.
wäre. Das heißt, hier hätte man als Zielpfad desmv
dann statt./..
auf einmal/..
. Ein katastrophaler Fehler, wenn jemals jemand den ersten Teil des Scripts abändert, so dass die Annahme nicht mehr gilt (zum Beispiel indem man die Dateinamen aus Nutzereingaben nimmt), ohne den kompletten Ablauf und alle Fallstricke der Expansion zu durchdenken, wodirname
die solidere Wahl gewesen wäre, weil es ohne Trickserei das ausdrückt, was man erreichen möchte.Shell-Tricks sind zwar schön und cool, aber man trickst sich damit auch gerne selbst aus, eventuell erst nach langer Zeit, wenn man vergessen hat, dass die Funktionsweise von einem Script, das man ändert, von solch einem Kniff abhängt. Ob die daraus folgenden Kopfschmerzen den Coolnessfaktor wert sind, muss man selber wissen. Produktiv in einer Umgebung, wo das verlässlich funktionieren muss, und wo noch andere Leute daran arbeiten, würde ich so etwas tunlichst vermeiden.