2016-05-04 2 views
1

MISE À JOUR: ce problème se produit lors de l'exécution d'outils de ligne de commande JVM dans un shell bash cygwin. Bien que je pensais initialement que cela était lié à Scala, il est spécifique à la machine virtuelle Java Windows. Cela peut être le résultat de briser des modifications dans les bibliothèques MSDN, voir les commentaires ci-dessous. Je suis en train d'écrire un script d'utilitaire scala qui prend une entrée de chemin de classe littérale java et l'analyse. Je voudrais que ma méthode principale puisse recevoir des arguments de ligne de commande avec un astérisque final, par exemple, "/ *", mais il semble qu'il n'y ait aucun moyen de le faire lors d'une session cygwin bash.Astérisques de fin sur les fenêtres Les arguments de ligne de commande JVM sont globalisés dans le shell cygwin bash

Voici mon script de test scala, qui affiche des arguments de ligne de commande:

# saved to a file called "dumpargs.sc" 
args.foreach { printf("[%s]\n",_) } 

Je voudrais pouvoir l'appeler avec un astérisque comme argument, comme celui-ci:

scala -howtorun:script dumpargs.sc "*" 

quand je lance ce dans une coquille cmd.exe, il fait ce que je pense:

c:\cygwin> scala.bat -howtorun:script dumpargs.sc "*" 
arg[*] 
c:\cygwin> 

de même, lorsqu'il est testé dans un Linux bash shell, l'unique argument de la ligne de commande consiste en un seul astérisque nu, comme prévu. Un programme de vidage d'arguments en ligne de commande écrit en C affiche un seul astérisque nu, quel que soit le shell à partir duquel il est exécuté (CMD.EXE ou bash). Toutefois, lorsque le même test est exécuté dans un shell cygwin bash, l'astérisque est globalisé et répertorie tous les fichiers du répertoire en cours. La globalisation se produit quelque part en aval d'après bash, sinon le programme C dumper aurait également échoué.

Le problème est subtil, il se produit quelque part dans la JVM après réception de l'argument astérisque et avant que la machine virtuelle Java appelle la méthode principale. Mais la JVM ne fait que glober l'astérisque en fonction de quelque chose dans l'environnement de l'environnement en cours d'exécution. D'une certaine façon, ce comportement est une bonne chose, car il supporte la portabilité des scripts, en masquant les différences dans les environnements d'exécution, Windows contre Linux/OSX, etc (les shells de type unix ont tendance à glob, alors que CMD.EXE ne pas).

Tous les efforts pour contourner le problème jusqu'à présent ont échoué:

Même si je suis pour permettre à des tours dépendant de l'OS, j'ai essayé tous les éléments suivants (d'une session bash):

"*" '*' '\*' '\\*' 

Ce qui suit fonctionne presque, mais les demi-citations arrivent dans le cadre de la valeur de l'argument et doit alors été écorchée par mon programme:

"'*'" 

même problème, mais différents types de unwan Les citations ted passent à travers:

'"*"' or \"*\" 

Ce qui est nécessaire est une propriété système ou un autre mécanisme pour désactiver la globalisation. Par ailleurs, une variante de ce problème est l'impossibilité de tirer parti de la manière agréable dont un répertoire de fichiers jar peut être ajouté au classpath (depuis java 1.6), en spécifiant "-classpath 'lib/*' ".

Il doit y avoir une propriété système que je peux définir pour désactiver ce comportement lors de l'exécution dans un environnement shell qui fournit son propre globbing.

+0

Le problème disparaît si les tests dans une session Linux. En outre, lors de l'appel de scala.bat à partir d'une session CMD.EXE, l'astérisque peut être placé entre guillemets doubles pour éviter le problème. Cela peut indiquer une opportunité de résoudre ce problème dans le script bash scala, puisque scala.bat peut être configuré pour fonctionner. – philwalk

+0

voir https://msdn.microsoft.com/en-US/library/ms235497(v=VS.80).aspx – philwalk

+0

Ceci peut être la source du bug: https://bugs.openjdk.java.net/ browse/JDK-7167744 bien qu'il se réfère à java 1.7 et le problème existe toujours en 1.8 plus tard en mai 2016. – philwalk

Répondre

0

Ce problème est causé par un bogue connu dans la machine virtuelle Java, documentée ici:

https://bugs.openjdk.java.net/browse/JDK-8131329

En attendant, pour contourner le problème, je passe des arguments via une variable d'environnement.

Voici ce qui se passe dans mon "myScalaScript":

#!/usr/bin/env scala 
for(arg <- args.toList ::: cpArgs){ 
    printf("[%s]\n",arg) 
} 

lazy val cpArgs = System.getenv("CP_ARGS") match { 
    case null => Nil 
    case text => text.split("[;|]+").toList 
} 

Voici comment le script est appelé à partir bash: "| ./lib/*" CP_ARGS = myScalaScript [peut-être autre-non problematic- args]

et voici ce qu'il imprime dans tous les environnements testés:

[.] 
[./lib/*] 

Voici une meilleure solution, qui cache toutes les méchancetés dans le script, et est un peu plus conventionnel dans la boucle principale.

Le nouveau script:

#!/bin/bash 
export CP_ARGS="[email protected]" 
exec $(which scala) "$0" 
!# 
// vim: ft=scala 

for(arg <- cpArgs){ 
    printf("[%s]\n",arg) 
} 

lazy val cpArgs = System.getenv("CP_ARGS") match { 
    case null => Nil 
    case text => text.split("[;|]+").toList 
} 
+0

parce que c'est une solution de contournement plutôt qu'une solution, j'attendrai une réponse (j'espère) meilleure. – philwalk

+0

BTW, je considère que le bogue jvm est assez sévère, car il empêche l'utilisation du raccourci de chemin de classe "tous les bocaux sous un répertoire", par exemple, -cp "./lib/*" dans un shell Windows bash. – philwalk

+0

"tous les bocaux sous un répertoire" idiome vérifié pour fonctionner dans Windows avec java 1.8.0_52 (éventuellement plus tôt), mais seulement si backslash est utilisé. La barre oblique fonctionne dans Windows java pour spécifier le chemin de classe en général, mais pas pour cet idiome particulier. – philwalk