Kabuk işlevlerini xargs ile çağırma


169

Paralel olarak daha karmaşık bir işlevi çağırmak için xargs kullanmaya çalışıyorum.

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
seq -f "n%04g" 1 100 |xargs -n 1 -P 10 -i echo_var {} 
exit 0

Bu hatayı döndürür

xargs: echo_var: No such file or directory

Bunu başarmak için xargs'ı nasıl kullanabileceğime dair herhangi bir fikir veya başka bir çözüm (ler) memnuniyetle karşılanacaktır.


2
Tehlike, user1148366, Tehlike! Paralel programlama için bash kullanmayın - çok fazla sorunla karşılaşırsınız. C / C ++ ve pthreads veya Java iş parçacıklarını veya yaptığınız şey hakkında uzun ve zor düşünmenizi sağlayan herhangi bir şey kullanın, çünkü paralel programlamanın doğru olması çok düşünülür.
David Souther

27
@DavidSouther Tüm bağımsız resim dosyalarını png'ye dönüştürmek gibi görevler bağımsızsa, endişelenmeyin. Senkronizasyon (herkesin bitmesini beklemenin ötesinde) ve iletişimin dağınık hale geldiği zamandır.
ctrl-alt-delor

@DavidSouther - Ben uzun zamandır Java dev ve ben geç groovy çalışıyorum. Ve insanlara söylemeye devam ediyorum: Arkadaşlar arkadaşların bash senaryosu yazmasına izin vermez. Ve yine de, kendimi bu yazıya / çözüme bakarken buluyorum çünkü (üzgün yüz :() Bash'da paralel işleme yapıyorum. Bunu groovy / java'da kolayca yapabilirim. Kötü!
Christian Bongiorno

Yanıtlar:


172

İşlevin dışa aktarılması bunu yapmalıdır (denenmemiş):

export -f echo_var
seq -f "n%04g" 1 100 | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

printfHarici yerine yerleşik olanı kullanabilirsiniz seq:

printf "n%04g\n" {1..100} | xargs -n 1 -P 10 -I {} bash -c 'echo_var "$@"' _ {}

Ayrıca return 0ve bunun exit 0gibi bir yöntem kullanıldığında, kendisinden önceki komutun üretebileceği hata değerlerini maskeler. Ayrıca, herhangi bir hata yoksa, varsayılan ve bu nedenle biraz gereksizdir.

@phobic Bash komut bahseder olabilir için Basitleştirilmiş

bash -c 'echo_var "{}"'

{}doğrudan içinde hareket . Ama bu kadar komut enjeksiyonu karşı savunmasız @Sasha tarafından belirttiği gibi.

Katıştırılmış biçimi kullanmamanız için bir örnek :

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "{}"'
Sun Aug 18 11:56:45 CDT 2019

Neden olmasın başka bir örnek :

echo '\"; date\"' | xargs -I {} bash -c 'echo_var "{}"'

Güvenli biçimi kullanarak çıktı budur :

$ echo '$(date)' | xargs -I {} bash -c 'echo_var "$@"' _ {}
$(date)

Bu, enjeksiyondan kaçınmak için parametreli SQL sorguları kullanmakla karşılaştırılabilir .

Ben kullanıyorum datebir komut yerine ya kaçan tırnak burada yerine içinde rmo tahribatsız beri Sasha yorumunda kullanılan komuta.


14
Biraz daha tartışma: xargs adlı yeni bir işlem örneğini çalıştırır. Bu durumda, echo_varPATH'nizde bir işlem (program) değil, bu komut dosyasındaki bir işlev olan adı sağlarsınız. Dennis'in çözümünün yaptığı şey, çocuk bash işlemlerinin işlevini dışa aktarmak, daha sonra alt işleme çatallar ve orada yürütmektir.
David Souther

7
önemi nedir _ve \onlarsız benim için çalışmıyor
Hashbrown

9
@Hashbrown: çizgi ( _) bir yer için tutucu sağlar argv[0]( $0) ve orada kullanılabilir neredeyse her şeyi. Sanırım maddeyi \;sonlandırmadaki kullanımı nedeniyle ters eğik çizgi-noktalı virgül ( ) ekledim , ama burada olmadan benim için çalışıyor. Aslında, işlev bunun yerine kullanılacaksa , noktalı virgülü bir parametre olarak görür, bu yüzden atlanmalıdır. -execfind$@$1
sonraki duyuruya kadar duraklatıldı.

4
-i xargs argümanı kullanımdan kaldırılmıştır. Bunun yerine -I (büyük harf i) kullanın.
Nicolai S

11
Bash için komut dizesine xargs değişkenini ekleyerek bunu basitleştirebilirsiniz bash -c 'echo_var "{}"'. Yani sonunda _ {} 'ye ihtiyacınız yok.
fobik

16

GNU Parallel kullanmak şu şekildedir:

#!/bin/bash
echo_var(){
    echo $1
    return 0
}
export -f echo_var
seq -f "n%04g" 1 100 | parallel -P 10 echo_var {} 
exit 0

20170822 sürümünü kullanıyorsanız export -f, bunu çalıştırdığınız sürece bile yapmanız gerekmez :

. `which env_parallel.bash`
seq -f "n%04g" 1 100 | env_parallel -P 10 echo_var {} 

osx için nereden alışveriş yapabilirim?
Nick

nvm zsh içinde setopt olduğunu
Nick

Bunu eerror Ole sh: parallel_bash_environment: line 67: unexpected EOF while looking for matching '' sh: parallel_bash_environment: satır 79: sözdizimi hatası: beklenmeyen dosya sonu sh: parallel_bash_environment' /usr/local/bin/bash: parallel_bash_environment: line 67: unexpected EOF while looking for matching '' / usr / local / bin / bash: parallel_bash_environment: line 79: sözdizimi hatası: beklenmeyen sonu file / usr / local / bin / bash: `... için işlev tanımını içe aktarma hatası
Nick

Shellaftershocked oldunuz: Shellshock, GNU Paralel'i doğrudan etkilemedi. Bununla birlikte, kabuk darbesi için çözüm: --env ve env_parallel hile tamamen kırdı. Git sürümünde düzeltildiğine inanılıyor: git.savannah.gnu.org/cgit/parallel.git/snapshot/…
Ole Tange

1
Bu yanıtı beğendim, çünkü paralel aracı keşfetmemi
sağladı

10

Bunun gibi bir şeyin de çalışması gerekir:

function testing() { sleep $1 ; }
echo {1..10} | xargs -n 1 | xargs -I@ -P4 bash -c "$(declare -f testing) ; testing @ ; echo @ "

1

Belki bu kötü bir uygulamadır, ancak bir .bashrcveya başka bir komut dosyasındaki işlevleri tanımlıyorsanız , dosyayı veya en azından işlev tanımlarını aşağıdaki ayarlarla sarabilirsiniz allexport:

set -o allexport

function funcy_town {
  echo 'this is a function'
}
function func_rock {
  echo 'this is a function, but different'
}
function cyber_func {
  echo 'this function does important things'
}
function the_man_from_funcle {
  echo 'not gonna lie'
}
function funcle_wiggly {
  echo 'at this point I\'m doing it for the funny names'
}
function extreme_function {
  echo 'goodbye'
}

set +o allexport
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.