Xargs'ın ikili yerine takma ad kullanmasını sağlama


14

CentOS 6.5'te Bash 4.2:

Benim ~/.bash_profilede dahil olmak üzere bir dizi takma ad var:

alias grep='grep -n --color=always'

Böylece renk vurgulama ve satır numaralarını otomatik olarak yazdırabilirim grep. Aşağıdakileri çalıştırırsam, vurgulama beklendiği gibi çalışır:

$ grep -Re 'regex_here' *.py

Ancak, bunu son zamanlarda çalıştırdığımda:

$ find . -name '*.py' | xargs grep -E 'regex_here'

sonuçlar vurgulanmadı ve satır numaraları yazdırılmadı, beni geri dönüp komuta açıkça eklemem -n --color=alwaysiçin zorladı grep.

  • Ortamdaki xargstakma adları okumuyor mu ?
  • Değilse, bunu yapmanın bir yolu var mı?

Bu soru ve cevap istediğinizi içerir.
psimon

@psimon doğru, bu aslında benim geçici çözümde zaten ne yaptığını söylemek - xargskomutta takma adı el ile genişletmek zorunda kaldı . Öğrenmeye çalıştığım şey, takma adımı doğrudan arayabileceğim bir yol olup olmadığıdır xargs.
MattDMo

1
export GREP_OPTIONS='-n --color=always'Xargs komutundan önce denedin mi?
doneal24

@ DougO'Neal teşekkürler, işe yaradı! Bunu ekleyeceğim .bash_profile. Cevap yazmaktan çekinmeyin ...
MattDMo

Yanıtlar:


11

Bir diğer ad, tanımlandığı kabuğun içindedir. Diğer işlemler tarafından görülemez. Aynı şey kabuk işlevleri için de geçerlidir. xargskabuk olmayan ayrı bir uygulamadır, bu nedenle takma ad veya işlev kavramına sahip değildir.

Xargs'ın grepdoğrudan çağırmak yerine bir kabuk çağırmasını sağlayabilirsiniz . Ancak sadece bir kabuk çağırmak yeterli değildir, o kabuktaki diğer adı da tanımlamanız gerekir. Takma ad, öğenizde tanımlanmışsa .bashrcbu dosyayı kaynaklayabilirsiniz; ancak bu, .bashrcetkileşimli olmayan bir kabukta anlamlı olmayan diğer görevleri gerçekleştirdiğinizde çalışmayabilir .

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E regex_here "$@"' _

Normal ifadeyi yazarken iç içe alıntıların karmaşıklıklarına dikkat edin. Normal ifadeyi kabuğa parametre olarak geçirerek hayatınızı kolaylaştırabilirsiniz.

find . -name '*.py' | xargs bash -c '. ~/.bashrc; grep -E "$0" "$@"' regex_here

Takma ad aramasını açıkça gerçekleştirebilirsiniz. Sonra xargsgöreceksiniz grep -n --color=always.

find . -name '*.py' | xargs "${BASH_ALIASES[grep]}" regex_here

Zsh dilinde:

find . -name '*.py' | xargs $aliases[grep] regex_here

Bu arada, find … | xargs … boşluk içeren dosya adlarını (diğerleri arasında) bozduğunu unutmayın . Boş sınırlandırılmış kayıtlara geçerek bunu düzeltebilirsiniz:

find . -name '*.py' -print0 | xargs -0 "${BASH_ALIASES[grep]}" regex_here

veya şunu kullanarak -exec:

find . -name '*.py' -exec "${BASH_ALIASES[grep]}" regex_here {} +

Aramak yerine, findher şeyi tamamen kabuğun içinde yapabilirsiniz. Glob paterni **/dizinleri tekrar tekrar dolaşır. Bash'da, shopt -s globstarönce bu glob desenini etkinleştirmek için koşmanız gerekir .

grep regex_here **/*.py

Bunun bazı sınırlamaları vardır:

  • Çok sayıda dosya eşleşirse (veya uzun yolları varsa), komut maksimum komut satırı uzunluğunu aştığı için başarısız olabilir.
  • Bash ≤4.2'de (ancak daha yeni sürümlerde ya da ksh veya **/zsh'da ), dizinlere sembolik bağlar halinde geri çekilir.

Başka bir yaklaşım, MariusMatutiae tarafından önerildiği gibi süreç ikamesini kullanmaktır .

grep regex_here <(find . -name '*.py')

Bu **/geçerli olmadığında kullanışlıdır : karmaşık findifadeler için veya h4.2 basamağında sembolik bağlar altında geri almak istemediğinizde. Bunun boşluk içeren dosya adlarını bozduğunu unutmayın; bir çözüm, globbing'i ayarlamak IFSve devre dışı bırakmaktır , ancak biraz karmaşık olmaya başlar:

(IFS=$'\n'; set -f; grep regex_here <(find . -name '*.py') )

takma adların neden diğer süreçler tarafından görülemediğinin açık bir açıklaması için teşekkür ederiz
MattDMo

Süreç ikamesi de kullanılabilir, cevabımı görün.
MariusMatutiae

11

kullanım alias xargs='xargs '

alias: alias [-p] [name[=value] ... ]
(snip)
A trailing space in VALUE causes the next word to be checked for
alias substitution when the alias is expanded.

Bunun için teşekkürler, sondaki uzay hilesini bilmiyordum.
MattDMo

Np. Aynı zamanda sudo
1.61803

2

Lütfen bunu ilgili SO sorusunda bulamadığım başka bir yaklaşımın bir gösterimi olarak kabul edin :

xargsİlk bağımsız değişkenin takma ad olup olmadığını kontrol eden ve buna göre genişleten bir sarmalayıcı işlevi yazabilirsiniz .

İşte tam olarak bunu yapan bir kod ama ne yazık ki Z kabuğu gerektirir ve bu nedenle bash ile 1: 1 çalışmaz (ve açıkçası, bunu taşımak için yeterince bash için kullanılmaz ):

xargs () {
        local expandalias
        if [[ $(which $1) =~ "alias" ]]; then
                expandalias=$(builtin alias $1) 
                expandalias="${${(s.'.)expandalias}[2]}"
        else
                expandalias=$1
        fi
        command xargs ${(z)expandalias} "${(z)@[2,-1]}"
}

Kanıt, işe yaradığını:

zsh% takma ad grep = "grep -n" ´                           # eşleşmenin satır numarasını dahil et
zsh% find foo -adı "* .p *" | xargs grep -E testi
foo / bar.p0: 151: # veri = Test
foo / bar.p1: 122: # veri = test # satır numaraları dahil
zsh% unalias grep 
zsh% find foo -adı "* .p *" | xargs grep -E testi
foo / bar.p0 # verileri = Test
foo / bar.p1: # veri = test # satır numaraları dahil değil
zsh% 

1

Daha basit ve daha zarif bir çözüm, işlem ikamesini kullanmaktır :

grep -E 'regex_here' <( find . -name '*.py')

Boru gibi yeni bir kabuk oluşturmaz, bu da takma adın tanımlandığı orijinal kabuğunuzda olduğunuz anlamına gelir ve çıktı tam olarak olmasını istediğiniz şeydir.

Yeniden yönlendirme ve parantez arasında boşluk bırakmamaya dikkat edin, aksi takdirde bash hata verir. Bildiğim kadarıyla, süreç ikamesi Bash, Zsh, Ksh {88,93} tarafından destekleniyor, ancak pdksh tarafından desteklenmiyor ( bunun henüz olmaması gerektiği söylendi ).



Süreç ikamesi karmaşık findkomutlar için iyi bir yöntemdir , ancak boşluklara zarar verebileceğine ve olabildiğince kolayca düzeltilemediğine dikkat etmeniz gerekir find | xargs( -print0ve -0(veya geçiş yaparak -exec). Uygulanabilir olduğunda **/, daha basit ve daha sağlamdır.
Gilles 'SO- kötü olmayı bırak

0

grep, GREP_OPTIONS ortam değişkeninden bir dizi varsayılan seçenek okuyacaktır. Koyacaksan

 export GREP_OPTIONS='--line-number --color=always'

.bashrc dosyasında değişken alt kabuklara aktarılır ve beklediğiniz sonuçları alırsınız.


Ama koymayın --line-numberveya --color=alwaysiçinde GREP_OPTIONSsadece bir komut için olmadığı sürece, bu komut bir çok kıracak. --color=autoorada olması sorun değil, hepsi bu. Bu çizgiyi içine koymak .bashrcbir sürü şeyi kıracak.
Gilles 'SO- kötü olmayı bırak

@Gilles Kök hesabı için herhangi bir komut için takma ad ayarlamak veya varsayılan seçenekleri geçersiz kılmak kötü bir şeydir. Bir kullanıcı hesabı için bu seçeneklerin ayarlanmasının pek çok soruna neden olması olası değildir. Sorunlu herhangi bir kullanıcı komut dosyası ile gelemiyorum.
doneal24

Hemen hemen grep kullanan herhangi bir komut dosyası, bir varlığın varlığını test etmenin ötesine geçecek şekilde kırılacaktır. Örneğin, gelen /etc/init.d/cronsistemimde: value=`egrep "^${var}=" "$ENV_FILE" | tail -n1 | cut -d= -f2` . Veya dan /usr/bin/pdfjam: pdftitl=`printf "%s" "$PDFinfo" | grep -e … | sed -e …` . Diğer ad, komut dosyalarında görünmediği için sorun değildir.
Gilles 'SO- kötü olmayı bırak

@Gilles Böyle birçok senaryodan haberdarım. Gezemediğim kişiler genellikle sadece kök tarafından çalıştırılır (/etc/init.d/cron gibi). Şahsen, kullanıcı hesaplarımda tanımlanmış herhangi bir takma adım yok veya komutların varsayılan davranışını geçersiz kılmak için bir rc dosyasında veya ortam değişkenleri aracılığıyla seçenekler ayarlamıyorum. Kolaylık yerine öngörülebilirliği tercih ederim.
doneal24

Takma adlar, komut dosyaları tarafından görülmediği için öngörülebilirliği bozmaz. Ayarlama GREP_OPTIONS, --color=auto(bunun için tasarlanan şey) gibi birkaç seçenek hariç, öngörülebilirliği çok kötü bir şekilde kırıyor .
Gilles 'SO- kötü olmayı bırak
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.