Je veux garder tous les files ne se terminant pas par .bat
j'ai essayé
for f in $(ls | egrep -v .bat); do echo $f; done
et
for f in $(eval ls | egrep -v .bat); do echo $f; done
Mais les deux approches produisent le même résultat, car elles impriment tout. Alors que ls | egrep -v .bat
ls | egrep -v .bat
et eval ls | egrep -v .bat
eval ls | egrep -v .bat
travail en soi, s'il est utilisé en dehors de la boucle for
.
MODIFIER
Il est intéressant de voir que si je laisse le drapeau -v
, la boucle fait ce qu'elle devrait et répertorie tous les files se terminant par .bat
.
N'hésitez pas à modifier le titre de la question, car je n'étais pas certain du problème.
J'utilise GNU bash, version 4.1.10(4)-release (i686-pc-cygwin).
EXEMPLE
$ ls -l | egrep -v ".bat" total 60K -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 fsc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scala* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalac* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scaladoc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalap*
La command fonctionne, mais pas dans la boucle for.
$ for f in $(ls | egrep -v .bat); do echo $f; done fsc fsc.bat scala scala.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat
DEBUG $ set -x
mike@pc /cygdrive/c/Program Files (x86)/scala/bin $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls -hF --color=tty ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo fsc.bat fsc.bat // and so on
Quelques petites choses dans votre code:
$(...)
) sans définir $IFS
Laisser les extensions non cotées est l'opérateur split + glob. La valeur par défaut est la division sur l'espace, l'onglet et la nouvelle ligne. Ici, vous ne souhaitez splitter que sur newline, vous devez donc définir IFS comme cela sinon cela ne fonctionnera pas correctement si les noms de files contiennent des espaces ou des tabulations
set -f
. Laisser les extensions non cotées est l'opérateur split + glob. Ici, vous ne voulez pas de globulation, c'est-à-dire l'extension de caractères generics tels que scala*
dans la list des files correspondants. Lorsque vous ne voulez pas que le shell fasse du "globbing", vous devez le désactiver avec set -f
ls
aliasé à ls -F
Le problème ci-dessus est aggravé par le fait que vous avez alias à ls -F
. Ce qui ajoute /
aux directorys et *
aux files exécutables. Donc, en général, parce que scala
est exécutable, ls -F
produit scala*
, et en tant que model de globulation, il est étendu à tous les noms de files commençant par scala
ce qui explique pourquoi egrep -v
ne filter pas les files.
newline est aussi valide qu'un caractère dans un nom de file. Donc, parsingr la sortie de ls
ne fonctionne généralement pas . Par exemple, la sortie de ls
dans un directory contenant des files a et b
est la même que dans un directory contenant un file appelé a\nb
.
Au-dessus de egrep
filterra les lignes des noms de files, pas les noms de files
egrep
au lieu de grep -E
egrep
est obsolète. grep -E
est l'équivalent standard.
.
opérateur regex. Au-dessus, vous avez utilisé egrep
pour activer les expressions régulières étendues , mais vous n'utilisez aucun des opérateurs RE spécifiques. Le seul opérateur de RE que vous utilisez est .
pour correspondre à n'importe quel personnage, alors qu'il semble que ce n'est pas ce que vous vouliez. Donc, vous pourriez aussi bien avoir utilisé grep -F
ici. Ou utilisez grep -v '\.bat'
.
egrep .bat
va correspondre à n'importe quelle ligne qui contient n'importe quel caractère suivi par bat
– bat
, de sorte que c'est l'expression rationnelle qui signifie tout ce qui contient bat
– bat
pas en première position. Il aurait dû être grep -v '\.bat$'
.
$f
non coté Laisser une expansion non cotée est l'opérateur split + glob. Là, vous ne voulez ni l'un ni l'autre, donc $f
devrait être cité ( "$f"
).
echo
echo
développe les séquences d'échappement ANSI C dans ses arguments et / ou traite les strings comme -n
ou -e
fonction de l'implémentation de l' echo
(et / ou de l'environnement).
Utilisez printf
place .
for f in *; do case $f in (*.bat);; (*) printf '%s\n' "$f" esac done
Bien que s'il n'y a pas de file non caché dans le directory courant, celui-ci affichera toujours *
. Vous pouvez contourner cela en zsh
en changeant *
en *(N)
ou en bash
en exécutant shopt -s nullglob
.
Vous ne devriez pas utiliser ls
pour parsingr les files de cette façon.
D'abord, configurez extglob globstar par shopt -s extglob globstar
puis
for f in !(*.bat) do printf '%s\n' "$f" done
Utilisation de find
find . -type f ! -name '*.bat'
Utilisez l'opérateur de négation pour un traitement plus sûr des files.
Il n'y a rien d'insortingnsèquement erroné avec votre boucle for:
$ for f in $(ls | egrep -v .bat); do echo $f; done
Voici ma sortie pour la command ci-dessus:
$ for f in $(ls | egrep -v .bat); do echo $f; done fsc scala scalac scaladoc scalap
Une suggestion serait de citer l'argument à egrep
, comme ainsi:
$ for f in $(ls | egrep -v '.bat'); do echo $f; done
Jetez également un coup d'œil au wiki de Bash Pitfalls pour d'autres problèmes potentiels lors de l'écriture de scripts dans Bash comme ceci. En particulier, cela semble être la raison la plus plausible pour laquelle vous rencontrez ce problème. Vérifiez si vos files returnnés contiennent des espaces.
Une autre chose à essayer est d'activer le debugging prolixe de votre command bash, avant de l'exécuter afin que vous puissiez voir ce qui se passe dans les coulisses.
Cela permet le debugging:
$ set -x
Ensuite, exécutez votre command:
$ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls --color=auto ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo scala scala + for f in '$(ls | egrep -v .bat)' + echo scalac scalac + for f in '$(ls | egrep -v .bat)' + echo scaladoc scaladoc + for f in '$(ls | egrep -v .bat)' + echo scalap scalap
Puis désactivez-le:
$ set +x
Étant donné que les exemples fonctionnent bien sur un certain nombre de systèmes Linux natifs, le problème est probablement egrep
à Cygwin et / ou à certaines versions de bash
et egrep
. Je ferais particulièrement attention au séparateur de champs dans Bash, $IFS
pour voir s'il y a un problème entre les différents séparateurs de lignes sous Windows ( 0x0d,0x0a
) et Unix ( 0x0a
).
Je n'ai pas d'installation de Cygwin donc je n'ai pas de méthode pour prouver cette hypothèse.