J'ai un fichier (appelé par exemple list.txt
) qui contient des chemins d'accès relatifs aux fichiers, un chemin par ligne, c'est-à-dire quelque chose comme ceci:
foo/bar/file1
foo/bar/baz/file2
goo/file3
Je dois écrire un script bash qui traite un chemin à la fois, le divise à la dernière barre oblique, puis lance un autre processus en lui fournissant les deux parties du chemin sous forme d'arguments. Jusqu'à présent, je n'ai que la partie en boucle:
for p in `cat list.txt`
do
# split $p like "foo/bar/file1" into "foo/bar/" as part1 and "file1" as part2
inner_process.sh $part1 $part2
done
Comment puis-je me séparer? Cela fonctionnera-t-il dans le cas dégénéré lorsque le chemin ne comporte pas de barre oblique?
THX
Utilisez basename
et dirname
, c'est tout ce dont vous avez besoin.
part1=`dirname "$p"`
part2=`basename "$p"`
Une méthode correcte à 100% et qui est sûre pour les noms de fichiers comportant des espaces ou des symboles amusants (à condition que inner_process.sh
les traite correctement, mais c'est une autre histoire):
while read -r p; do
[[ "$p" == */* ]] || p="./$p"
inner_process.sh "${p%/*}" "${p##*/}"
done < list.txt
et il ne crée pas dirname
et basename
(dans les sous-shell) pour chaque fichier.
La ligne [[ "$p" == */* ]] || p="./$p"
est ici juste au cas où $p
ne contiendrait aucune barre oblique, alors il y ajouterait ./
.
Voir la section Shell Parameter Expansion dans le Manuel de référence Bash pour plus d'informations sur les symboles %
et ##
.
Pour répondre à la critique de @ gniourf_gniourf sur la réponse de @ piokuc tout en restant concise et simple (sinon aussi efficace):
part1=`dirname "$p"`
part2=`basename "$p"`
(J'aurais répondu dans un commentaire mais c'est syntaxiquement impossible.)
Excellente solution de cette source
p=/foo/bar/file1
path=$( echo ${p%/*} )
file=$( echo ${p##/*/} )
Cela fonctionne aussi avec des espaces dans le chemin!