Ich versuche, eine Variable in einem sh-Skript auf die letzten 3 Zeichen des Basisnamens einer Datei zu setzen (mit Basisname meine ich ohne Pfad und ohne Suffix). Ich habe es geschafft, aber ich frage mich, ob es einen kürzeren, einzelnen Befehl gibt, den ich aus Neugier verwenden kann. Ursprünglich hatte ich ein Einzeiler mit awk
, aber es war ziemlich lang. Derzeit habe ich dieses zweizeilige Skript (unter der Annahme, dass sich ein vollständiger Dateiname in befindet $1
):
filebase=`basename "$1"`
lastpart=`echo -n ${filebase%.*} | tail -c3`
So endet beispielsweise "/path/to/somefile.txt" mit "ile" in $lastpart
.
Kann ich irgendwie kombinieren basename
und das Bit, um das Suffix in einem einzigen Befehl zu trennen, und gibt es eine Möglichkeit, es an tail
(oder etwas anderes, das ich verwenden kann) zu senden, ohne eine Pipe zu verwenden? Das Suffix ist unbekannt, daher kann ich es nicht als Parameter verwenden basename
.
Das Hauptziel ist nicht, so kurz wie möglich zu sein, sondern auf einen Blick so gut wie möglich lesbar zu sein. Der eigentliche Kontext all dessen ist diese Frage zum Superuser , bei der ich versuche, eine einigermaßen einfache Antwort zu finden.
quelle
file.one.two.three
? Möchtest duile
odertwo
?two
würde funktionieren; die verlängerung dazu wäre wohl.three
ich.Antworten:
Das ist ein typischer Job für
expr
:Wenn Sie wissen, dass Ihre Dateinamen das erwartete Format haben (enthält nur einen Punkt und mindestens 3 Zeichen vor dem Punkt), können Sie Folgendes vereinfachen:
Beachten Sie, dass der Beendigungsstatus ungleich Null ist, wenn keine Übereinstimmung vorliegt, aber auch, wenn der übereinstimmende Teil eine Zahl ist, die auf 0 aufgelöst wird (wie für
a000.txt
odera-00.txt
).Mit
zsh
:(
:t
für Schwanz (Basisname),:r
für Rest (mit entfernter Erweiterung)).quelle
expr
ist eine andere, mit der ich mich vertraut machen muss. Ich wirklich wie diezsh
Lösungen im Allgemeinen (ich lese gerade über seine Unterstützung für verschachtelte Substitutionen auf der linken Seite eines${}
gestern zu und wünschtesh
das gleiche habe), es ist nur ein doofer , dass es nicht immer standardmäßig vorhanden ist.expr
war nicht POSIX. Es ist sicherlich. Es ist jedoch selten eingebaut.Das erste Mal werden die letzten drei Zeichen
$var
entfernt, danach werden$var
die Ergebnisse dieser Entfernung entfernt. Dabei werden die letzten drei Zeichen von zurückgegeben$var
. Hier sind einige Beispiele, die speziell zeigen sollen, wie Sie so etwas tun können:Sie müssen dies nicht durch so viele Befehle verbreiten. Sie können dies komprimieren:
Die Kombination
$IFS
mitset
ting-Shell-Parametern kann auch ein sehr effektives Mittel zum Parsen und Durchsuchen von Shell-Variablen sein:Dadurch erhalten Sie nur die drei Zeichen, die unmittelbar vor dem ersten Punkt nach dem letzten
/
in stehen$path
. Wenn Sie nur die ersten drei Zeichen unmittelbar vor dem letzten.
in abrufen möchten$path
(zum Beispiel, wenn der.
Dateiname möglicherweise mehrere ) :In beiden Fällen können Sie Folgendes tun:
Und...
... druckt was folgt
.
Wenn es Ihnen nichts ausmacht, ein externes Programm zu verwenden, können Sie Folgendes tun:
Wenn es die Möglichkeit gibt, dass
\n
der Dateiname ein ewline-Zeichen enthält (gilt nicht für native Shell-Lösungen - das erledigen sowieso alle) :quelle
$base
dort zu bekommen, war das Beste, was ich tun konnte, die drei Zeilenname=${var##*/} ; base=${name%%.*} ; lastpart=${base#${base%???}}
. Auf der positiven Seite ist es reine Bash, aber es sind immer noch 3 Zeilen. (In Ihrem Beispiel für "/tmp/file.txt" benötige ich "ile" anstelle von "file".) Ich habe gerade viel über das Ersetzen von Parametern gelernt. Ich hatte keine Ahnung, dass es das tun könnte ... ziemlich praktisch. Ich finde es auch persönlich sehr lesbar.%
anstatt es%%
zu verwenden, und ich muss den Pfad eigentlich nicht entfernen, damit ich eine schönere, zweizeilige Linie bekommenoextn=${var%.*} ; lastpart=${noextn#${noextn%???}}
.$IFS
in${noextn}
und Sie zitieren nicht die Erweiterung. Das ist also sicherer:lastpart=${noextn#"${noextn%???}"}
Wenn Sie verwenden können
perl
:quelle
perl -e 'shift =~ /(.{3})\.[^.]*$/ && print $1' $filename
. Ein zusätzlichesbasename
wäre erforderlich, wenn der Dateiname möglicherweise kein Suffix enthält, jedoch ein Verzeichnis im Pfad.perl -e 'shift =~ m#(.{3})(?:\.[^./]*)?$# && print $1' $filename
sed
funktioniert dafür:Oder
Wenn dein
sed
nicht unterstützt-r
, ersetzen Sie einfach die Instanzen()
mit\(
und\)
, und dann-r
ist nicht erforderlich.quelle
Wenn Perl verfügbar ist, kann es besser lesbar sein als andere Lösungen, insbesondere weil die Regex-Sprache aussagekräftiger ist und der
/x
Modifikator das Schreiben klarerer Regex- Zeichen ermöglicht:Dies gibt nichts aus, wenn es keine solche Übereinstimmung gibt (wenn der Basisname keine Erweiterung hat oder wenn der Stamm vor der Erweiterung zu kurz ist). Je nach Ihren Anforderungen können Sie die Regex anpassen. Dieser reguläre Ausdruck erzwingt die folgenden Einschränkungen:
Dies in einer Befehlsersetzung zu verwenden, hat die normalen Probleme, zu viele nachgestellte Zeilenumbrüche zu entfernen, ein Problem, das sich auch auf Stéphanes Antwort auswirkt. Es kann in beiden Fällen behandelt werden, ist aber hier etwas einfacher:
quelle
Python2.7
quelle
Ich denke, diese Bash-Funktion, pathStr (), wird das tun, wonach Sie suchen.
Es erfordert weder awk, sed, grep, perl noch expr. Es werden nur Bash-Buildins verwendet, daher ist es recht schnell.
Ich habe auch die abhängigen Funktionen argsNumber und isOption eingefügt, aber ihre Funktionen könnten leicht in pathStr integriert werden.
Die abhängige Funktion ifHelpShow ist nicht enthalten, da sie zahlreiche Abhängigkeiten für die Ausgabe des Hilfetextes über die Terminalbefehlszeile oder über YAD in ein GUI-Dialogfeld aufweist . Der übergebene Hilfetext dient der Dokumentation. Geben Sie an, ob Sie ifHelpShow und seine abhängigen Personen möchten.
RESSOURCEN
quelle
bash
Ismen - anscheinend einfacher als dies macht. Was ist das auch${#@}
?$#
die Syntax für die Anzahl der Argumente wird angegeben und hier auch an anderer Stelle verwendet.${#@}
ist in den meisten Fällen nicht äquivalent - die POSIX-Spezifikation gibt die Ergebnisse von Parametererweiterungen an$@
oder$*
ist leider nicht spezifiziert. Es kann funktionieren,bash
aber das ist keine zuverlässige Funktion, ich denke, das ist, was ich versuche zu sagen.