Je recherche une ligne élégante (par exemple, awk
) qui raccourcira une chaîne d'un chemin Unix en utilisant le premier caractère de chaque niveau parent / intermédiaire, mais le nom de base complet. Plus facile à montrer par des exemples:
/path/to/file
→/p/t/file
/tmp
→/tmp
/foo/bar/.config/wizard_magic
→/f/b/./wizard_magic
/foo/bar/.config/wizard_magic
→/f/b/.c/wizard_magic
À la lumière des bons points de @ MichaelKjörling et @ChrisH ci-dessous, cet exemple montre comment nous pouvons afficher les deux premiers caractères lorsque le premier caractère est un point.
/f/b/.c/wizard_magic
. Le point est souvent si commun dans un répertoire particulier qu'il est un très petit indice de l'endroit où vous devriez chercher..
signifie normalement "répertoire courant". C'est/f/b/./wizard_magic
la même chose que/f/b/wizard_magic
parce que l'élément de chemin se./
comprime en un élément de chemin vide.Réponses:
Pour ce fichier de test:
Les abréviations peuvent être générées avec ce code awk:
Edit1: Utilisation de deux caractères pour les noms de points
Cette version abrège les noms de répertoire en un seul caractère, à l'exception des noms commençant par
.
qui sont abrégés en deux caractères:Comment ça fonctionne
-F/
Cela indique à awk d'utiliser une barre oblique comme séparateur de champ en entrée.
for (i=1;i<NF;i++) $i=substr($i,1,1)
Cela boucle sur chaque champ, sauf le dernier, et le remplace par son premier caractère uniquement.
EDIT1: Dans la version révisée, nous faisons la longueur de la sous-chaîne 2 lorsque le champ commence par
.
.1
Cela indique à awk d'imprimer la ligne révisée.
OFS=/
Cela indique à awk d'utiliser une barre oblique comme séparateur de champ en sortie.
la source
‥
séparateur:awk -F/ '{for (i=1;i<NF;i++) $i=substr($i,1,1+($i~/^[.]/))(i==1||length($i)<2?"":"‥")} 1' OFS=/ <<<$PWD
donne:/foo/bar/.config/wizard_magic
→/f‥/b‥/.c‥/wizard_magic
Assez facile dans sed (en supposant qu'il n'y ait pas de nouvelle ligne dans les noms de fichiers):
Moins facile dans awk car il manque de références (sauf dans Gawk, mais avec une syntaxe maladroite):
En zsh (avec le chemin d'accès
$full_path
):la source
\1
dans la chaîne de remplacement ne signifie pas une référence à un groupe de capture dans le motif. Une référence est une référence, peu importe où vous l'utilisez.vous pouvez le faire comme:
et voici un
sed
:qui est assez proche de faire toutes les mêmes choses que la fonction ci-dessous. il n'abrège pas de tildes ni n'insère le
$PWD
dans la tête pour une non-barre oblique comme le fait la fonction (et en fait, n'imprime jamais la barre oblique) mais cela pourrait être géré par la suite. il traite les composants de chemin nul et les points uniques et élimine les..
cas.étant donné le même
man
chemin quecd
ci-dessus, il imprime:il imprimera également un ou deux points de tête supplémentaires pour chaque composant de chemin commençant par tel et non pas seulement un ou deux points.
vous avez demandé de faire plus que le seul caractère d'un composant de chemin commençant par un
.
. pour ce faire, je pensais que chaque composant aurait besoin d'une attention individuelle de toute façon, et parce que j'étais curieux, j'ai essayé de trouver un chemin canonique sans le répertoire de changement. après quelques essais et erreurs, j'ai finalement décidé que la seule façon de le faire correctement était de le faire deux fois - en arrière et en avant:de sorte que ne modifie jamais le répertoire ou n'essaie pas de confirmer l'existence d'un composant de chemin, mais il serre les
/
délimiteurs répétés et supprime/./
entièrement les composants à point unique, et traite/../
les composants à double point de manière appropriée.lorsque
$IFS
est défini sur un caractère non blanc , une séquence de deux caractères ou plus$IFS
se traduira par un ou plusieurs champs nuls. donc plusieurs barres obliques consécutives entraînent des arguments de valeur nulle. il en va de même pour un$IFS
personnage principal . et donc quandset -- $1
se divise, si le résultat$1
est nul alors il a commencé par une barre oblique, sinon,${1:+$PWD}
s'il n'est pas nul, alors j'insère$PWD
. en d'autres termes, si le premier argument ne commence pas par une barre oblique, il sera$PWD
ajouté au début . c'est aussi proche que cela vient de la validation du chemin .sinon, la première
for
boucle inverse récursivement l'ordre des composants du chemin, comme:... ce faisant, il ignore tous les composants à point unique ou nul, et pour
..
cela ...... le deuxième passage inverse cet effet, et ce faisant , il comprime chaque composant soit 2-points + carbonisation , ou 1-Dot + carbonisation ou de carbonisation .
il devrait donc fonctionner sur un chemin canonique indépendamment de l'existence.
j'ai ajouté / soustrait un peu à la deuxième boucle. elle est désormais
set
moins fréquente (une seule fois pour chaque[!./]*
composant) , et court-circuite lescase
évaluations de modèles la plupart du temps (grâce au modèle susmentionné) , et inclut une évaluation de correspondance d'appel final~
. si tout ou une partie principale (divisée sur des composants entiers) du chemin finalement canonique peut correspondre~
, le bit correspondant sera supprimé et un littéral~
sera substitué. Pour ce faire, j'ai dû également conserver une copie complète du chemin à côté de l'abrégé (car faire correspondre le chemin abrégé à~
ne serait probablement pas très utile) , et donc cela est conservé$3
. le dernierwhile
la branche de boucle n'est exécutée que si elle~
correspond à un sous-ensemble de$3
.si vous l'exécutez avec
set -x
trace activée, vous pouvez le regarder fonctionner.la source
Le thème "fishy" Zsh de Oh My Zsh contient un extrait Perl pour faire exactement cela qui prend en charge Unicode:
la source
Voulez-vous avoir un nom abrégé ou l'utiliser pour votre ligne de commande?
Pour la ligne de commande, j'ai les suggestions suivantes:
L'achèvement de fichier dans votre shell ne vous aide-t-il pas?
Parfois, vous avez de la chance et n'avez pas à faire quelque chose de spécial:
Lorsque vous n'avez que quelques répertoires qui vous intéressent, vous pouvez utiliser des alias:
Ou vous pouvez configurer des variables pour vos répertoires préférés
Je pense que ces options ont plus de sens que d'essayer de résoudre ce problème avec une fonction définie en .bashrc (ou .profile) comme
et en appelant cette fonction x avec des espaces entre vos lettres:
la source