2011-09-30 21 views
9

Sto tentando di utilizzare GNU parallel per inviare molti file su un server web. Nel mio elenco, ho alcuni file:"find" e "ls" con GNU parallel

file1.xml 
file2.xml 

e ho uno script di shell che assomiglia a questo:

#! /usr/bin/env bash 

CMD="curl -X POST [email protected]$1 http://server/path" 

eval $CMD 

C'è qualche altra roba nello script, ma questo era l'esempio più semplice. Ho cercato di eseguire il seguente comando:

ls | parallel -j2 script.sh {} 

Che è ciò che le pagine GNU parallel mostrano come il modo "normale" per operare su file in una directory. Questo sembra passare il nome del file nel mio script, ma ricciolo lamenta che non può caricare il file di dati in passato Tuttavia, se faccio:.

find . -name '*.xml' | parallel -j2 script.sh {} 

funziona benissimo. C'è una differenza tra il modo in cui ls e find stanno passando argomenti al mio script? O devo fare qualcosa di aggiuntivo in quella sceneggiatura?

+1

hai provato a provare con #!/ bin/bash -x che ti mostrerà se i tuoi argomenti non sono quelli che pensi dovrebbero essere. –

+0

Sono sempre imbarazzato quando ciò accade, ma quando ho provato a riprodurre questo problema il giorno successivo (e uso il -x come suggerito) non riuscivo a riprodurlo e tutto funzionava alla grande. Sono stato in grado di usare ls o trovare con successo ogni volta. Mi chiedo se in qualche modo ho messo a tacere il mio ambiente e un log out/a chiarito qualcosa. – Dave

risposta

2

Non ho usato parallel ma c'è un diverso tra ls & find . -name '*.xml'. ls elencherà tutti i i file e le directory dove come find . -name '*.xml' verranno elencati solo i file (e le directory) che terminano con uno .xml.
Come suggerito da Paul Rubel, è sufficiente stampare il valore di $ 1 nel proprio script per verificarlo. Inoltre, si consiglia di considerare di filtrare l'input per i file solo in find con l'opzione -type f.
Spero che questo aiuti!

1

Neat.

Non avevo mai usato il parallelo prima. Sembra, anche se ce ne sono due. Uno è Gnu Parrallel, e quello che è stato installato sul mio sistema ha Tollef Fog Heen elencato come autore nelle pagine man.

Come accennato Paolo, si dovrebbe usare set -x

Inoltre, il paradigma che lei ha citato sopra non sembra funzionare sul mio parallelo, anzi, devo di fare quanto segue:

$ cat ../script.sh 
+ cat ../script.sh 
#!/bin/bash 
echo [email protected] 
$ parallel -ij2 ../script.sh {} -- $(find -name '*.xml') 
++ find -name '*.xml' 
+ parallel -ij2 ../script.sh '{}' -- ./b.xml ./c.xml ./a.xml ./d.xml ./e.xml 
./c.xml 
./b.xml 
./d.xml 
./a.xml 
./e.xml 
$ parallel -ij2 ../script.sh {} -- $(ls *.xml) 
++ ls --color=auto a.xml b.xml c.xml d.xml e.xml 
+ parallel -ij2 ../script.sh '{}' -- a.xml b.xml c.xml d.xml e.xml 
b.xml 
a.xml 
d.xml 
c.xml 
e.xml 

find fornisce un input diverso, antepone il percorso relativo al nome. Forse è questo che rovina il tuo script?

5

GNU parallel è una variante di xargs. Entrambi hanno interfacce molto simili e se stai cercando aiuto su parallel, potresti avere più fortuna nella ricerca di informazioni su xargs.

Detto questo, il modo in cui entrambi funzionano è abbastanza semplice. Con il loro comportamento predefinito, entrambi i programmi leggono l'input da STDIN, quindi suddividono l'input in token basati su spazi bianchi. Ognuno di questi token viene quindi passato come argomento a un programma fornito. L'impostazione predefinita per xargs consiste nel passare più token possibile al programma e quindi avviare un nuovo processo quando viene raggiunto il limite. Non sono sicuro di come funziona l'impostazione predefinita per il parallelo.

Ecco un esempio:

> echo "foo bar \ 
    baz" | xargs echo 
foo bar baz 

Ci sono alcuni problemi con il comportamento di default, quindi è comune vedere diverse varianti.

Il primo problema è che, poiché gli spazi bianchi vengono utilizzati per la tokenizzazione, qualsiasi file con spazi vuoti in essi causerà la rottura di parallele e xarg. Una soluzione è tokenize attorno al carattere NULL invece. find fornisce anche un'opzione per rendere questo facile da fare:

> echo "Success!" > bad\ filename 
> find . "bad\ filename" -print0 | xargs -0 cat 
Success! 

L'opzione -print0 dice find per separare i file con il carattere NULL invece di spazi bianchi.
L'opzione -0 indica a xargs di utilizzare il carattere NULL per tokenizzare ogni argomento.

Si noti che parallel è un po 'meglio di xargs in quanto il suo comportamento predefinito è il tokenize attorno solo a linee nuove, quindi è meno necessario modificare il comportamento predefinito.

Un altro problema comune è che si potrebbe voler controllare come gli argomenti vengono passati a xargs o parallel. Se è necessario disporre di una posizione specifica degli argomenti passati al programma, è possibile utilizzare {} per specificare dove posizionare l'argomento.

> mkdir new_dir 
> find -name *.xml | xargs mv {} new_dir 

Ciò spostare tutti i file nella directory corrente e sottodirectory nella directory new_dir. In realtà si scompone in quanto segue:

> find -name *.xml | xargs echo mv {} new_dir 
> mv foo.xml new_dir 
> mv bar.xml new_dir 
> mv baz.xml new_dir 

in modo da prendere in considerazione come xargs e parallel lavoro, si dovrebbe teoricamente essere in grado di vedere il problema con il vostro comando. find . -name '*.xml' genererà un elenco di file xml da passare al programma script.sh.

> find . -name '*.xml' | parallel -j2 echo script.sh {} 
> script.sh foo.xml 
> script.sh bar.xml 
> script.sh baz.xml 

Tuttavia, ls | parallel -j2 script.sh {} genererà un elenco di tutti i file nella directory corrente da passare al programma script.sh.

> ls | parallel -j2 echo script.sh {} 
> script.sh some_directory 
> script.sh some_file 
> script.sh foo.xml 
> ... 

una più corretta variante della versione ls sarebbe come segue:

> ls *.xml | parallel -j2 script.sh {} 

Tuttavia, e importante differenza tra questa e la versione scoperta è che la trovano saranno la ricerca in tutte le sottodirectory per i file, mentre ls cercherà solo la directory corrente. La versione equivalente find del comando precedente ls sarebbe la seguente:

> find -maxdepth 1 -name '*.xml' 

Questo cercherà solo la directory corrente.

3

Dal momento che funziona con find probabilmente si desidera vedere quale comando GNU Parallel è in esecuzione (utilizzando -v o --dryrun) e quindi provare a eseguire manualmente i comandi in errore.

ls *.xml | parallel --dryrun -j2 script.sh 
find -maxdepth 1 -name '*.xml' | parallel --dryrun -j2 script.sh