Utiliser la substitution de variable bash au lieu de cut / awk

Puis-je utiliser la substitution de variable bash pour extraire une partie dune variable basée sur un délimiteur? Jessaye dobtenir le nom de répertoire immédiat dun nom de fichier (dans ce cas, foo).

$ filename=./foo/bar/baz.xml 

Je sais que je pourrais faire quelque chose comme

echo $filename | cut -d "/" -f 2 

ou

echo $filename | awk -F "/" "{print $2}" 

mais ça  » s devient lent à fork awk / cut pour plusieurs noms de fichiers.

Jai fait un petit profilage des différentes solutions , en utilisant mes vrais fichiers:

echo | couper:

real 2m56.805s user 0m37.009s sys 1m26.067s 

echo | awk:

real 2m56.282s user 0m38.157s sys 1m31.016s 

@steeldriver « substitution de variable / extension des paramètres de shell:

real 0m0.660s user 0m0.421s sys 0m0.235s 

@jai_s « s IFS-wrangling:

real 1m26.243s user 0m13.751s sys 0m28.969s 

Les deux suggestions étaient une énorme amélioration par rapport à mes idées existantes, mais la substitution de variable est plus rapide car elle ne le fait pas nécessite de bifurquer tout nouveau processus.

Commentaires

  • gnu.org/software/bash/manual / html_node / …
  • Envoyez tous les noms de fichiers à une seule invocation de awk et ce sera beaucoup plus rapide que nimporte quelle solution en pure bash
  • Ne pouvez-vous pas utiliser un tableau, faites-les tous en même temps puis mettez-le dans un nouveau tableau?

Réponse

Vous pouvez supprimer la sous-chaîne de début la plus courte correspondant à */

tmp="${filename#*/}" 

, puis supprimer la plus longue sous-chaîne de fin qui correspond à /*

Réponse

 echo $f a/b/c $ (IFS="/";set $f; echo $1) a $ (IFS="/";set $f; echo $2) b $ (IFS="/";set $f; echo $3) c 

avec un caractère générique avec lequel il semble fonctionner guillemets doubles ou simples –

 f="a?b?c" $(IFS="?"; set $f; echo $1) a echo $f a*b*c (IFS="*"; set $f; echo $1) a 

oui, vous « devrez rétablir lIFS par défaut

 unset IFS 

Commentaires

  • Ooh, jaime ça.
  • Cest généralement ma méthode préférée aussi, mais gardez à lesprit que Bash prend uniquement en charge $1 à $9 en utilisant cette syntaxe. Pour le 10e argument et les suivants, la forme ${10} doit être utilisée.
  • Ne ' t fonctionne lorsque $f contient des caractères génériques. Et vous devez restaurer IFS par la suite (ou faire cela dans une substitution de commande, pour obtenir la valeur dun champ, et cela supprime les nouvelles lignes de fin).
  • Lexemple fonctionne de manière isolée (à lintérieur de Git bash sous Windows), mais lorsque je lance la commande find, jobtiens cette erreur: echo: write error: Bad address.
  • Daccord, ça ressemble à Je dois unset IFS à chaque fois.

Répondre

Flux la liste à awk pour laccélérer:

awk -F "/" "{print $2}" < <(find /usr) awk -F "/" "{print $2}" < inputfile 

Démonstration:

time awk -F "/" "{print $2; SUM++} END {print "number of directories found: " SUM}" < <(find /usr -type d) usr usr . . number of directories found: 16748 real 0m8.910s user 0m0.050s sys 0m0.050s 

Réponse

Pourquoi nutilisez-vous pas la commande » dirname « , au lieu de tout cela awk / sed / couper des trucs?

filename=./foo/bar/baz.xml dirname $filename 

Rendements:

./foo/bar 

Commentaires

  • Dans ce cas, je cherchais le répertoire immédiat, pas le chemin complet du répertoire.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *