J'essaie d'utiliser find -name
dans un script sh
avec un argument complexe précédemment calculé pour la condition. Simplifié, ça va comme
cond="-name '*.txt*" find . $cond -ls
Mais maintenant, j'ai le problème que soit le caractère générique dans $cond
est étendu par le shell avant d'appeler find
ou non développé par find
.
Pour tester cela, dans un directory de test vide j'ai fait:
touch a.txt b.txt c.dat
et ensuite itéré
cond="-name '*.txt'"; echo $cond; find . $cond
avec des valeurs différentes pour $cond
, en utilisant tous les types de citations / échappées auxquelles je pourrais penser.
Soit j'obtiens les quatre inputs (y compris le directory .
) Ou aucun file – ou find
plaintes à propos de b.txt
étant un primaire ou un opérateur inconnu. Bien sûr, la sortie correcte devrait être juste les deux files text.
Des conseils? Je suis sûr que je manque juste quelque chose de basique.
Dans les shells de type Bourne (excepté zsh
), en laissant une expansion variable non cotée dans le context de list, l'opérateur split + glob . Dans:
cond="-name '*.txt'"; echo $cond
Le contenu de $cond
est d'abord divisé selon la valeur de la variable spéciale $IFS
. Par défaut, c'est sur l'espace ASCII, l'onglet et les caractères de nouvelle ligne.
Donc, c'est divisé en -name
et '*.txt'
. Ensuite, la partie glob est appliquée. Pour chacun de ces mots contenant des caractères generics (ici *
dans le second), le mot est étendu à la list des files qui correspondent à ce model ou laissés intacts si aucun file n'est associé. Ainsi, '*.txt'
s'étend à la list des files du directory courant dont le nom commence par '
et se termine par .txt'
ou '*.txt'
si aucun file ne correspond.
Cette list de mots est ensuite passée en tant qu'arguments séparés à echo
. Si aucun file ne correspond, cela signifie que echo
recevra 3 arguments: "echo"
, "-name"
et "'*.txt'"
.
Bien sûr, la même chose s'applique à la command find
.
Vous voulez que la command find
reçoive les arguments -name
et *.txt
, vous devez donc régler votre opérateur split + glob .
Vous avez besoin de la valeur de $IFS
pour correspondre au séparateur que vous utilisez dans $cond
. Donc par exemple:
cond='-name:*.txt' IFS=':'
Et vous ne voulez pas la partie glob de l'opérateur split + glob , vous devez donc le désactiver avec:
set -f
Donc ça devient:
cond='-name:*.txt' IFS=:; set -f find . $cond -ls
Ou vous pourriez faire:
cond='-name *.txt' set -f find . $cond -ls
et supposons que $IFS
n'a pas été modifié par rapport à sa valeur par défaut.
Alternativement, si votre shell prend en charge les arrays, vous pouvez utiliser cela au lieu de countr sur des variables scalaires et attendre que le shell le divise lors de l'expansion.
Cela fonctionnerait avec ksh93
, mksh
, bash
ou zsh
:
cond=(-name '*.txt') # an array with two elements: "-name" and "*.txt" find . "${cond[@]}" -ls # elements of the array expanded as separate arguments # to find.