Stdin girişi boşsa xargs komutlarını nasıl yok sayabilirim?


189

Bu komutu düşünün:

ls /mydir/*.txt | xargs chown root

Amaç, tüm metin dosyalarının sahiplerini mydirkökten değiştirmek

Sorun, eğer .txtdosya yoksa mydiro zaman xargs belirtilen bir yol olmadığını söyleyen bir hata çözer. Bu zararsız bir örnektir, çünkü bir hata atılır, ancak bazı durumlarda, burada kullanmam gereken komut dosyasında olduğu gibi, boş bir yolun geçerli dizin olduğu varsayılır. Bu komutu oradan çalıştırırsam, /home/tom/sonuç yoksa ls /mydir/*.txtve altındaki tüm dosyalar /home/tom/sahiplerinin kök değiştirmesini sağlar.

Peki xargs'ın boş bir sonucu yoksaymasını nasıl sağlayabilirim?


6
Bir kenara: lsProgramlı kullanım için asla boru çıkışını yapmayın ; bkz. mywiki.wooledge.org/ParsingLs
Charles Duffy

Kullanım durumum git branch --merged | grep -v '^* ' | xargs git branch -dda boş girişte başarısız oluyor
belkka

Yanıtlar:


305

GNU xargsiçin -rveya --no-run-if-emptyseçeneğini kullanabilirsiniz :

--no-run-if-empty
-r
Standart giriş herhangi bir boşluk içermiyorsa, komutu çalıştırmayın. Normalde komut, giriş olmasa bile bir kez çalıştırılır. Bu seçenek bir GNU oluşumudur.


9
Dürüst olmak gerekirse ilk google'da aradı ve bu bulundu (ama kılavuzu okumadan sormak olmazdı). Bu tür varsayılan davranış olacağını düşündüm, etkinleştirmek için bir anahtara gerek yok.
JonnyJD

28
Ne yazık ki bu bir Mac üzerinde çalışmaz. Ne kısa ne de uzun seçenek.
wedi

9
@wedi - OSX'in BSD kullanıcı alanı vardır, bu nedenle bu tür şeyler sık ​​sık gerçekleşir. GNU dosya kurulumlarını yüklemek için homebrew kullanarak bu sorunu çözebilirsiniz.
edk750

7
Yani brew install findutils. findutils, değil fileutils.
Mitar

3
MacOS'ta, bayrağı sağlamazsanız, komutun yine de çalıştırılmaması gerekir, bu yüzden sanırım sadece gerekli değildir.
Trejkaz

15

GNU dışı Xargs kullanıcıları avantajını ait alabilir -L <#lines>, -n <#args>, -i, ve -I <string>:

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder

Xargs'ın boşluğa satır ayırdığını, ancak alıntı ve kaçmanın mümkün olduğunu unutmayın; Ayrıntılar için RTFM.

Ayrıca, Doron Behar'ın belirttiği gibi, bu geçici çözüm taşınabilir değildir, bu nedenle kontroller gerekebilir:

$ uname -is
SunOS sun4v
$ xargs -n1 echo blah < /dev/null
$ uname -is
Linux x86_64
$ xargs --version | head -1
xargs (GNU findutils) 4.7.0-git
$ xargs -n1 echo blah < /dev/null
blah

2
Bu soruya cevap vermiyor mu?
Nicolas Raoul

2
@Nicolas: sürümünüz anahtarı xargsdesteklemiyorsa --no-run-if-emptyve STDIN girişi olmadan komut bağımsız değişkenini çalıştırmayı denerse (Solaris 10'da durum budur) yürütmeyi önlemenin yoludur . Diğer unixlerdeki sürümler boş bir listeyi yoksayabilir (örn. AIX).
arielCo

4
Evet! MAC OSX'te echo '' | xargs -n1 echo blahhiçbir şey yapmaz; oysa echo 'x' | xargs -n1 echo blah"falan" basar.
carlosayam

2
Hem GNU hem de BSD / OSX desteği için ls /mydir/*.txt | xargs -n 1 -I {} chown root {}bu cevabın önerdiği gibi:
Luís Bianchin

3
Bu unutulmamalıdır echo '' | xargs -n1 echo blahbaskılar blahGNU en ile xargs.
Doron Behar

11

man xargsdiyor --no-run-if-empty.


1
OSX kullanıyorsanız, olmayacak. edk750, nedenini merak ediyorsanız yorumlarında bunu açıkladı.
jasonleonhard

9

Açısından, önerildiği gibi xargskullanabilirsiniz -r, ancak BSD tarafından desteklenmez xargs.

Geçici çözüm olarak, fazladan geçici bir dosya aktarabilirsiniz, örneğin:

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)

veya stderr değerini null ( 2> /dev/null) biçimine yönlendirin , ör.

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true

Başka bir daha iyi yaklaşım, whiledöngü kullanarak bulunan dosyalar üzerinde yineleme yapmaktır :

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  chown -v root "$file"
done

Ayrıca bkz: Mac OS X'te xargs için boş sonuçları yoksay


Ayrıca, izinleri değiştirme yönteminizin mükemmel olmadığını ve cesaretinin kırıldığını lütfen unutmayın. Kesinlikle lskomut çıktısını ayrıştırmamalısınız (bkz: Neden ls çıktısını ayrıştırmamalısınız ). Özellikle komutunuzu root ile çalıştırdığınızda, dosyalarınız kabuk tarafından yorumlanabilen veya etrafında boşluk karakteri olan dosyanın hayal edilebileceği özel karakterler içerebileceğinden /, sonuçlar korkunç olabilir.

Bu nedenle yaklaşımınızı değiştirmeli ve findbunun yerine komutu kullanmalısınız, örn.

find /mydir -type f -name "*.txt" -execdir chown root {} ';'

1
Maalesef, bunun nasıl while IFS= read -r -d '' filegeçerli olduğunu anlamıyorum . Açıklayabilir misin?
Adrian

2

OSX'te: Argümanla xargsbaşa çıkmanın Bash'in yeniden uygulanması, -rbunu örneğin içine koyun $HOME/binve aşağıdakilere ekleyin PATH:

#!/bin/bash
stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
    # shift the arguments to get rid of the "-r" that is not valid on OSX
    shift
    # wc -l return some whitespaces, let's get rid of them with tr
    linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]') 
    if [ "x$linecount" = "x0" ]
    then
      exit 0
    fi
fi

# grep returns an error code for no matching lines, so only activate error checks from here
set -e
set -o pipefail
echo $stdin | /usr/bin/xargs $@

2

Bu, -r, --no-run-if-empty kullanılarak bastırılabilen GNU xargs davranışıdır.

Xargs * BSD varyantı varsayılan olarak bu davranışa sahiptir, bu nedenle -r gerekmez. FreeBSD 7.1'den (Ocak 2009'da yayınlanmıştır) beri uyumluluk nedeniyle bir -r argümanı kabul edilir (cadı hiçbir şey yapmaz).

Ben şahsen betiklerde longopts kullanmayı tercih ediyorum ama * BSD xargs longopts kullanmadığından sadece "-r" kullanın ve xargs linux sistemlerde * BSD ve

MacOS'taki xargs (şu anda MacOS Mojave) ne yazık ki "-r" argümanını desteklemiyor.

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.