Récupère un élément de la chaîne de chemin à l'aide de bash

9

J'ai un fichier ASCII contenant des chemins de fichiers que je lis en exécutant:

while read p; do echo $p; done < filelist.txt

Le fichier contient des chemins de fichier avec le modèle suivant:

./first/example1/path
./second/example1/path
./third/example2/path

Comment puis-je obtenir une partie spécifique de la chaîne de chemin (de /à /), par exemple, j'ai besoin d'obtenir une sortie qui affiche:

first
second
third

et aussi

example1
example1
example2

Je suis sûr qu'il existe un moyen de le faire en utilisant des expressions régulières et sed, mais je ne le connais pas.

mcExchange
la source

Réponses:

17

Utilisation cut:

$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

$ cut -d/ -f2 filelist.txt 
first
second
third

$ cut -d/ -f3 filelist.txt 
example1
example1
example2

Le -d/définit le délimiteur de colonne sur /et -f2sélectionne la 2e colonne.

Vous pouvez bien sûr également utiliser des variables Bash au lieu d'un nom de fichier ou de données de canal dans la cutcommande:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
Byte Commander
la source
L'utilisation | cut -d/ -f3 dans une pipe a fait l'affaire. Merci! C'est la commande complète maintenant: while read p; do echo $p; done < filelist.txt | cut -d/ -f3
mcExchange
3
@mcExchange Il n'y a aucune raison d'utiliser cette boucle while. C'est beaucoup plus simple à faire cut -d/ -f3 filelist.txt
Monty Harder
1
De plus, éviter le tout évite les problèmes de citation et n'échouera pas avec les sauts de ligne dans les noms de fichiers.
Volker Siegel
10

Vous pouvez le faire directement dans votre readcommande, en utilisant IFSpar exemple la variable

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
tournevis
la source
5

Vous pouvez utiliser awk

pilot6@Pilot6:~$ cat filelist.txt
./first/example1/path
./second/example1/path
./third/example2/path

pilot6@Pilot6:~$ awk -F "/" '{print $2}' filelist.txt
first
second
third

pilot6@Pilot6:~$ awk -F "/" '{print $3}' filelist.txt
example1
example1
example2
Pilot6
la source
3

Si nous voulons un élément du chemin, il est préférable d'utiliser quelque chose qui peut diviser une chaîne en champs, comme , ,, ou . cependant, peut également faire le travail avec la substitution de paramètres, en utilisant le remplacement de modèle et en jetant tout dans un tableau.

$> echo ${FILE//\//\ }                                                         
sys class backlight intel_backlight brightness
$> ARRAY=( ${FILE//\//" " } )                                                  
$> echo ${ARRAY[2]}
backlight

$> FILE="./dir1/dir2/file.txt"                                                 
$> ARRAY=( ${FILE//\/" "} )
$> echo ${ARRAY[@]}                                                            
. dir1 dir2 file.txt
$> echo ${ARRAY[1]}
dir1

Nous avons maintenant un tableau d'éléments fabriqués à partir du chemin. Notez que si le chemin contient des espaces, cela peut impliquer de modifier le séparateur de champ interne IFS.

Sergiy Kolodyazhnyy
la source
1

Bash et cutsont la voie à suivre, cependant une alternative en utilisant Perl:

perl -F/ -lane 'print(@F[1])' filelist.txt

pour le deuxième /champ délimité et

perl -F/ -lane 'print(@F[2])' filelist.txt

pour le troisième /champ délimité.

  • -l: active le traitement automatique de fin de ligne. Il a deux effets distincts. Tout d'abord, il chomps automatiquement $ / (le séparateur d'enregistrement d'entrée) lorsqu'il est utilisé avec -n ou -p. Deuxièmement, il affecte $ \ (le séparateur d'enregistrements de sortie) à la valeur d'octnum afin que toutes les instructions d'impression aient ce séparateur ajouté à nouveau. Si octnum est omis, définit $ \ à la valeur actuelle de $ /.
  • -a: active le mode de fractionnement automatique lorsqu'il est utilisé avec -n ou -p. Une commande de division implicite au tableau @F est effectuée comme première chose à l'intérieur de la boucle while implicite produite par -n ou -p.
  • -n: oblige Perl à assumer la boucle suivante autour de votre programme, ce qui le fait parcourir les arguments de nom de fichier un peu comme sed -n ou awk:

    LINE:
      while (<>) {
          ...             # your program goes here
      }
  • -e: peut être utilisé pour entrer une ligne de programme;

  • print(@F[N]): imprime le Nième champ.
% cat filelist.txt 
./first/example1/path
./second/example1/path
./third/example2/path
% perl -F/ -lane 'print(@F[1])' filelist.txt
first
second
third
% perl -F/ -lane 'print(@F[2])' filelist.txt
example1
example1
example2
kos
la source