Les documents sont stockés dans un système de fichiers qui comprend des répertoires "quotidiens", par exemple 20050610. Dans un script bash script je veux lister les fichiers de ces répertoires pour un mois. Je lance donc la commande find find <path>/200506* -type f >> jun2005.lst
. J'aimerais vérifier que cet ensemble de répertoires n'est pas un ensemble nul avant d'exécuter la commande find. Cependant, si j'utilise if[ -d 200506* ]
Je reçois un message d'erreur "too many arguements error". Comment puis-je contourner ce problème ?
Réponses
Trop de publicités?L'erreur "trop d'arguments" ne provient pas du fait qu'il y a un grand nombre de fichiers et que la limite d'arguments de la ligne de commande est dépassée. Elle vient du fait qu'il y a plus d'un ou deux répertoires qui correspondent au glob. Votre globule "200506*" se développe en quelque chose comme "20050601 20050602 20050603..." et la commande -d
n'attend qu'un seul argument.
$ mkdir test
$ cd test
$ mkdir a1
$ [ -d a* ] # no error
$ mkdir a2
$ [ -d a* ]
-bash: [: a1: binary operator expected
$ mkdir a3
$ [ -d a* ]
-bash: [: too many arguments
La réponse de zed_0xff est sur la bonne voie, mais j'utiliserais une approche différente :
shopt -s nullglob
path='/path/to/dirs'
glob='200506*/'
outfile='jun2005.lst'
dirs=("$path"/$glob) # dirs is an array available to be iterated over if needed
if (( ${#dirs[@]} > 0 ))
then
echo "directories found"
# append may not be necessary here
find "$path"/$glob -type f >> "$outfile"
fi
La position des guillemets dans "$path"/$glob
par rapport à "$path/$glob"
est essentielle à ce travail.
Editer :
Des corrections ont été apportées pour exclure les fichiers qui correspondent au mot-clé (de sorte que seuls les répertoires sont inclus) et pour gérer le cas très inhabituel d'un répertoire nommé littéralement comme le mot-clé ("200506*").
S=200506*
if [ ${#S} -gt 6 ]; then
echo haz filez!
else
echo no filez
fi
pas très élégante, mais sans outils/commandes externes (si on ne considère pas "[" comme un outil externe)
l'indice est que si certains fichiers correspondent, la variable "S" contiendra leurs noms délimités par des espaces. Sinon, elle contiendra elle-même une chaîne "200506*".
La plupart des shells limitent la longueur des lignes de commande : tout ce qui ressemble à "$(ls -d | grep 200506)" ou à /chemin/200506* risque de dépasser la limite. Je ne sais pas si les substitutions et les expansions globales sont prises en compte dans BASH, mais je suppose que oui. Il faudrait le tester et consulter la documentation et les sources de BASH pour s'en assurer.
La réponse se trouve dans la simplification de votre question.
find <path>/200506* -type f -exec somescript '{}' \;
Où somescript est un shell script qui effectue le test. Quelque chose comme ceci peut-être :
#!/bin/sh
[ -d "$@" ] && echo "$@" >> june2005.lst
Passer le fichier june2005.lst au script (conseil : utiliser une variable d'environnement), et gérer la possibilité que 200506* puisse s'étendre à un chemin de fichier trop énorme, étant laissé comme un exercice pour l'OP ;)
L'intégration de l'ensemble dans un pipe line ou l'adaptation d'un langage de script plus général permettrait d'améliorer les performances, en minimisant le nombre de coquilles créées. Voilà qui serait amusant. Voici un conseil : utilisez -exec et un autre programme (awk, perl, etc.) pour effectuer le test de répertoire dans le cadre d'un filtre d'une ligne, et conservez le fichier >>june2005.lst dans la commande find.