web-dev-qa-db-fra.com

Obtenir un élément de chaîne de chemin en utilisant bash

J'ai un fichier ASCII contenant les chemins de fichiers que j'ai lu en exécutant:

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

Le fichier contient des chemins de fichiers avec le motif suivant:

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

Comment obtenir une partie spécifique de la chaîne de chemin d'accès (de / à /), par exemple J'ai besoin d'un résultat qui imprime:

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 bien.

8
mcExchange

Utilisez 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

-d/ définit le délimiteur de colonne sur / et le -f2 sélectionne la deuxième colonne.

Vous pouvez bien sûr aussi utiliser des variables Bash au lieu d'un nom de fichier ou transmettre des données dans la commande cut:

cut -d/ -f3 $MyVariable
echo ./another/example/path | cut -d/ -f3
14
Byte Commander

Vous pouvez le faire directement dans votre commande read, à l’aide de la variable IFS, par exemple.

$ while IFS=/ read -r p1 p2 p3 r; do echo "$p2"; done < filelist.txt 
first
second
third
10
steeldriver

Vous pouvez utiliser awkname__

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
5
Pilot6

Si nous voulons n'importe quel élément du chemin, il est préférable d'utiliser quelque chose qui peut diviser une chaîne en champs, tel que awk , cut , python , ou Perl . Cependant, bash peut également effectuer le travail avec la substitution de paramètres, en utilisant le remplacement de modèle et en jetant le 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’articles créé à partir du chemin. Notez que si le chemin contient des espaces, il peut être nécessaire de modifier le séparateur de champ interne IFSname__.

2

Bash et cut sont la voie à suivre, mais une alternative 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 de fin de ligne automatique. Il a deux effets distincts. Premièrement, il chomps automatiquement $/(le séparateur d'enregistrement d'entrée) lorsqu'il est utilisé avec -n ou -p. Deuxièmement, il attribue à $\(le séparateur d'enregistrement de sortie) la valeur d'octnum afin que toutes les instructions d'impression ajoutent ce séparateur. Si octnum est omis, définit $\sur la valeur actuelle de $ /.
  • -a: active le mode autosplit lorsqu'il est utilisé avec un -n ou -p. Une commande de fractionnement implicite dans le tableau @F est effectuée en premier dans la boucle while implicite produite par -n ou -p.
  • -n: Perl assume la boucle suivante autour de votre programme, ce qui le rend itératif sur 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]): affiche 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
1
kos