[RESOLVIDO] Caractere * como argumento de linha de comando

4 respostas Resolvido
java
sanrox

Boa tarde, amigos!

Estou com um pequeno problema com relação aos argumentos via linha de comando para executar um .jar

Criei um projeto que deve aceitar parâmetros de forma interativa com o usuário, caso não haja argumentos via “String[] args” na main()…
Portanto a rotina de validação dos argumentos é a mesma para o modo interativo e para o modo “linha de comando”, sendo que a forma interativa está funcionando perfeitamente. Porém por uma convenção muito comum uma simples execução via linha de comando está sendo desafiadora…

Em síntese, o projeto consiste em atualizar uma base com dados de outras bases em outros servidores, cada um com suas características particulares, mas todas as peculiaridades estão sendo tratadas.

Vamos lá!

java -jar new.jar

Caso não fosse detectado nada no String args[], o programa interagiria com o usuário solicitando alguns argumentos de forma manual, até aqui tudo OK!

java -jar new.jar 1 2 3 2019 5

aqui estou executando uma tarefa para a base “1”, estatística “2”, mês “3”, ano “2019”, índice “5”
dessa forma o jar é executado perfeitamente.
Obs.: a linha de comando será necessária pois o processo é bem demorado e deverá ser executado de forma automática na madrugada, graças a um .sh (bash - Linux)

Porém, lembra da convenção?
De forma interatividade eu posso passar cada argumento com o valor : * (asterisco) (Funcionando)
E todos devem ter ideia que * pode significar “TODOS”
Pois bem, se eu passar os argumentos da seguinte forma (linha de comando):
java -jar new.jar * * * 2019 *
Em teoria deveria ser : todas as bases , todas as estatísticas , todos os meses , ano “2019”, todos os índices.
Mas o resultado é esse:

java -jar new jar * * * 2019 *
java.lang.NumberFormatException: For input string: "BKP_listagemSG190813.war"
** at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)**
** at java.lang.Integer.parseInt(Integer.java:580)**
** at java.lang.Integer.parseInt(Integer.java:615)**
** at view.ExtratorConsole.validateSystemArgs(ExtratorConsole.java:323)**
** at view.ExtratorConsole.main(ExtratorConsole.java:102)**
O campo Sistema está incorreto…
Aplicação Encerrada!!!

Dando um sysout nos args:
args[0] = BKP_listagemSG190813.war
args[1] = extrator
args[2] = extrator_passado2.sh
args[3] = HelloWorld.war
args[4] = IMetas180611.war

O que está acontecendo aqui é que o sistema entende que o * significa “TODOS OS ARQUIVOS”, logo é como se tivesse passando todos os arquivos do diretório do .jar como parâmetro.

É um desafio que compartilho com os caros colegas

Obs. é possível contornar isso de uma maneira não muito elegante. Por exemplo:
java -jar new.jar “" "” “" 2019 "
(abre aspas asterisco fecha aspas)

ou de outra forma, mas eu gostaria da ajuda dos colegas pra saber se é possível realizar a chamada da seguinte forma:
java -jar newMetas.jar * * * 2019 *

Obrigado!

4 Respostas

darlan_machado

Eu entendo que o problema não é com os parâmetros, mas, com o tratamento dos mesmos. Afinal, como você mesmo disse, caso sejam passados entre aspas, funciona.
Sem ver código, difícil.

sanrox

Não estou no ambiente de trabalho no momento, mas é simples fazer um teste:

public class Arg {

public static void main(String[] args) {
	
	System.out.println("args[0] = " + args[0]);
	System.out.println("args[1] = " + args[1]);
	System.out.println("args[2] = " + args[2]);
	System.out.println("args[3] = " + args[3]);
	System.out.println("args[4] = " + args[4]);
	
}

}

teste 1

java -jar Arg.jar 0 1 2 3 4

args[0] = 0
args[1] = 1
args[2] = 2
args[3] = 3
args[4] = 4

teste 2

java -jar Arg.jar * 1 2 3 4

args[0] = .classpath
args[1] = .project
args[2] = .settings
args[3] = bin
args[4] = src

Vc pode perceber que com o asterisco sem aspas , é interpretado como se todos os arquivos do diretório corrente fossem argumentos do programa.
Então independente do tratamento, os argumentos já chegam alterados antes mesmo de fazer qualquer validação/tratamento.

lvbarbosa
Solucao aceita

O caractere * é interpretado pelo shell como todos os arquivos do diretório atual. Esse comportamento se chama globbing. Tem duas formas de desligar: escapar o asterisco ou desligar o globbing:

set -o noglob

Os argumentos que você está passando depois do asterisco ainda estão no array args, só não estão na posição que você espera. Faz um loop e imprime todos os argumentos que você vai ver que eles estão lá.

sanrox

De fato essa configuração tem que ser feita para desabilitar o glob no Linux…
E após a execução essa configuração tem que ser revertida com

set +o noglob

Muito Obrigado pela solução.
Mas agora ficam outros problemas, por exemplo, para ser de forma automática um .sh deveria ser escrito para desativar o glob, rodar a aplicação com os parâmetros e após isso reativar o glob…

Mas caso a aplicação seja chamada por um usuário via linha de comando, o mesmo terá que desativar manualmente o glob…

E no windows como ficaria?

Enfim, mas isso já não é problema do java e sim característica de cada shell.

Obrigado!

Criado 11 de setembro de 2019
Ultima resposta 12 de set. de 2019
Respostas 4
Participantes 3