Newsgroup: it.comp.www.php
Titolo: riga di comando: separare i parametri dalle opzioni

Ho creato il seguente script:
 
<?php // cli.php
echo "OPZIONI:\n";
print_r(getopt('xyz'));
 
echo "PARAMETRI:\n";
print_r($argv);
?>
 
Adesso lo mando in esecuzione (da terminale linux)
 
php cli.php -x -y -z a b c
 
ed ottengo il seguente output:
 
OPZIONI:
Array
(
     [x] =>
     [y] =>
     [z] =>
)
PARAMETRI:
Array
(
     [0] => cli.php
     [1] => -x
     [2] => -y
     [3] => -z
     [4] => a
     [5] => b
     [6] => c
)
 
Dunque, per quanto riguarda le opzioni, ci siamo!!!
Ma per estrarre solo i dati (i parametri), cioè
 
     [4] => a
     [5] => b
     [6] => c
 
come posso fare?


La butto lì:
array_splice($argv, count(getopt('xyz'))+1));
 
Ciao!

come posso fare?
 
$parameters = array_filter(
	array_slice($argv, 1),
	function($uozz) use ($opzioni) {
		// Questo per ignorare qualunque opzione
		return ('-' !== substr($uozz, 0, 1));
		// Questo ignora solo le $opzioni
		return	('-' !== substr($uozz, 0, 1))
			|| !array_exists(
				substr($uozz, 1),
				$opzioni
			);
	});
 
Leonardo
 
-- 
A stultis ex omnibus gentium varie pictis
A sanctae fidei adeptis, ab eorum odore;
AB insanis Iacobinis, ab eorum ardore
AB idolatris et martyribus odii et terroris;
A paradisi fautoribus dicentibus "est pro amore",
A manichaeis ululantibus "Nisi nobiscum prodes";
LIBERA, libera, libera, libera nos, Domine.

 array_splice($argv, count(getopt('xyz'))+1));
 
- parentesi di troppo
- 0 mancate
 
versione corretta:
 
     array_splice($argv, 0, count(getopt('xyz')) + 1);
 
Direi che va bene, ma possibile che in php non esiste una funzione 
interna che segue perfettamente le convenzioni ufficiali?

array_splice($argv, count(getopt('xyz'))+1));
 
Bisogna specificare pero' che le opzioni precedono obbligatoriamente tutti gli
argomenti.



 
Questa risponde anche a Leonardo:
 
Di solito non ci sono parametri "extra" dopo le opzioni: le opzioni /sono/
i parametri!
Se hai, mettiamo, due switch e due file in input, usi un formato tipo:
-x -y -f <file1> -w <file2>
 
che parsi con:
getopt("xyf:w:")
 
che ti tirerà fuori qualcosa tipo
array('x'=>, 'y'=> 'f'=>'file1', 'w'=>'file2')
 
almeno, su unix così si fa.
 
Ciao!

 almeno, su unix così si fa.
 
beh come sopra...
 
Ad ogni modo è sorto un altro problema
 
$ php cli.php -j -k -x -y -z a b c
OPZIONI:
Array
(
     [x] =>
     [y] =>
     [z] =>
)
PARAMETRI:
Array
(
     [0] => -y
     [1] => -z
     [2] => a
     [3] => b
     [4] => c
)
 
le opzioni "-j -k" hanno fatto slittare "-y -z" nei parametri :-(

 le opzioni "-j -k" hanno fatto slittare "-y -z" nei parametri :-(
 
dopo
$opts = getopt("jkxyz");
controlli che l'opzione sia settata o meno con
isset($opts['j']) o isset($opts['x'])
 
Ciao!

 isset($opts['j']) o isset($opts['x'])
 
a questo punto dovrei fare
getopt('abcdefghijklmno...')
e controllarli tutti uno per uno; no assolutamente :D
Alla luce di tutto questo, naturalmente tralasciamo eventuali 
long-options :)


 
Se scrivi come vorresti la tua riga di comando, o le opzioni e parametri
che il tuo programma deve prendere, sono sicuro che possiamo scriverti
come faremo noi al tuo posto - magari prendi spunto ;)
 
Ciao!

 come faremo noi al tuo posto - magari prendi spunto ;)
 
$ php test.php -z -h -m -s -a -b -x -c -y par1 par2 par3
 
dunque, all'applicazione servono:
- i paramtri: par1, par2, par3
- le opzioni: -a, -b, -c
 
tutto il resto sono opzioni che l'utente magari ha scritto per sbaglio, 
per cui vanno ignorate.
Ma comunque devono sempre far parte dell'array delle opzioni, e non 
finire nell'array dei parametri. Oppure, ancora meglio, finire in un 
terzo array (array delle opzioni non riconosciute), e magari generare un 
apposito errore per segnalare che appunto tali opzioni non sono state 
riconosciute.


Ok, senza pensarci troppo, e prendendo pezzi dalla documentazione ufficiale,
io farei così (ma controlla!):
 
<?php
$options = getopt('abc');
 
/* remove opts form argv */
$pruneargv = array();
foreach ($options as $option => $value) {
  foreach ($argv as $key => $chunk) {
      $regex = '/^'. (isset($option[1]) ? '--' : '-') . $option . '/';
      if ($chunk == $value && $argv[$key-1][0] == '-' || preg_match($regex, $chunk))
          array_push($pruneargv, $key);
  }
}
/* remove look-alike opts from argv */
foreach ($argv as $key => $chunk) {
    if (!in_array($key, $pruneargv) && $chunk[0]=='-') {
        echo "warning: unknown option $chunk\n";
        array_push($pruneargv, $key);
    }
}
/* apply */
while ($key = array_pop($pruneargv)) unset($argv[$key]);
 
/* remove program option */
array_shift($argv);
 
/* final arrays */
print_r($options);  /* options */
print_r($argv);     /* parameters */
?>
 
 
Fa quello che vuoi.
Poi vedi te se ti piace, o sennò spero ora sia facile metterci una pezza :)
 
Ciao!

 Poi vedi te se ti piace, o sennò spero ora sia facile metterci una pezza:)
 
alla fine si deve fare un parsing manuale...


Nope.
Se ti sembra complesso quello che ti ho scritto, un "parsing manuale" non
l'hai nemmeno mai visto.
Prova a fare lo stesso senza getopts e senza array, poi mi riscrivi :)
 
Ciao!

 alla fine si deve fare un parsing manuale...
 
Questa divisione in "opzioni" e "argomenti" è convenzionale (== solo 
nella tua testa), sono solo elementi in un array di stringhe.
Se vuoi imporre una struttura, ad esempio prima tutte le opzioni  e poi 
gli argomenti, la devi per forza controllare e restituire un errore 
perché il sistema operativo non lo farà, e a ragione.
Quando fai questo controllo ricordati che non puoi solo controllare se 
la stringa comincia con un trattino perché potrebbe essere una opzione 
con argomento che convenzionalmente si può presentare in molte maniere, 
con e senza spazio:
-o value
-ovalue
-o:value
--option value
--option=value
--option:value
 
Alcuni non rispettano nemmeno la convenzione - e -- per le opzioni 
corte e lunghe.
 
Il concetto fondamentale è che argv is argv is argv.
 
 
-- 
Andrea
 


si, cmq purtroppo una funzione che fa il discernimento, seguendo in toto 
gli standard pseudo-ufficiali non esiste, e, in certi casi, bisogna per 
forza farsi un po' di menate...
 


La funzione che segue gli standard è quella, getopt, ma le tue necessità
sono personali (warning in caso d'errore, tre file di input, etc.) e
non puoi aspettarti di trovare una funzione che faccia esattamente quello
che vuoi!
 
In ogni caso come vedi non è difficile scriversela, per cui poco male :)
 
Ciao!