Bir komutun boş bir dize çıkıp çıkmadığını nasıl sınayabilirim?
ifne
. joeyh.name/code/moreutils
Bir komutun boş bir dize çıkıp çıkmadığını nasıl sınayabilirim?
ifne
. joeyh.name/code/moreutils
Yanıtlar:
Önceden, soru bir dizinde dosya olup olmadığını nasıl kontrol edeceğinizi soruyordu. Aşağıdaki kod bunu başarır, ancak daha iyi bir çözüm için rsp'nin cevabına bakın .
Komutlar değer döndürmez - çıktı verir. Komut değiştirme kullanarak bu çıktıyı yakalayabilirsiniz ; örn $(ls -A)
. Bash'te boş olmayan bir dizeyi şu şekilde test edebilirsiniz:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Bunun -A
yerine -a
sembolik current ( .
) ve parent ( ..
) dizin girişlerini atladığı için kullandığımı unutmayın .
Not: Yorumlarda belirtildiği gibi, komut ikamesi sondaki satırları yakalamaz . Bu nedenle, komut yalnızca yeni satırlar çıkarırsa, ikame hiçbir şey yakalamaz ve sınama false değerini döndürür. Çok olası olmasa da, yukarıdaki örnekte bu mümkündür, çünkü tek bir yeni satır geçerli bir dosya adıdır! Bu cevapta daha fazla bilgi .
Komutun başarıyla tamamlandığını kontrol etmek isterseniz $?
, son komutun çıkış kodunu içeren (başarı için sıfır, hata için sıfır olmayan) inceleyebilirsiniz. Örneğin:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
Daha fazla bilgi burada .
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
Orijinalimi geliştirmek için bir öneri için netj'e teşekkürler :if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
Bu eski bir soru ama bazı iyileştirme veya en azından açıklığa kavuşturulması gereken en az iki şey görüyorum.
Gördüğüm ilk sorun, burada verilen örneklerin çoğunun işe yaramadığı . Her ikisi de boş dizinlerde boş olmayan dizeler çıkaran ls -al
ve ls -Al
komutlarını kullanırlar . Bu örnekler her zaman dosya olmasa bile dosya olduğunu bildirir .
Bu nedenle sadece kullanmalısınız ls -A
- Neden herkes -l
herhangi bir çıktı olup olmadığını test etmek için "uzun bir liste formatı kullan" anlamına gelen anahtarı kullanmak istesin ki, yine de herhangi bir çıktı olup olmadığını test etmek?
Yani buradaki cevapların çoğu yanlış.
İkinci sorun ise olmasıdır bazı cevaplar cezası çalışmak (o bu değil kullanmak ls -al
veya ls -Al
ancak ls -A
hepsi böyle bir şey yapmak yerine):
Bunun yerine ne önerirsiniz:
using head -c1
Örneğin, yerine:
if [[ $(ls -A) ]]
Kullanmak istiyorum:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
Onun yerine:
if [ -z "$(ls -lA)" ]
Kullanmak istiyorum:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
ve bunun gibi.
Küçük çıktılar için sorun olmayabilir, ancak daha büyük çıktılar için fark önemli olabilir:
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
Şununla karşılaştırın:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
Ve daha da iyisi:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Will Vousden'in cevabından güncellenen örnek:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Netj tarafından yapılan önerilerden sonra tekrar güncellendi :
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
Jakeonfire tarafından ek güncelleme :
grep
eşleşme yoksa hata ile çıkılır. Sözdizimini biraz basitleştirmek için bundan yararlanabiliriz:
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
Test ettiğiniz komut boş bir dize olarak değerlendirmek istediğiniz bazı boşluklar verebilirse, bunun yerine:
| wc -c
kullanabilirsin:
| tr -d ' \n\r\t ' | wc -c
veya head -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
ya da böyle bir şey.
İlk olarak, çalışan bir komut kullanın .
İkincisi, RAM'de gereksiz yere saklamaktan ve potansiyel olarak büyük verilerin işlenmesinden kaçının.
Cevap, çıktının her zaman küçük olduğunu belirtmedi, bu nedenle büyük çıktı olasılığının da dikkate alınması gerekiyor.
[[ $(... | head -c | wc -c) -gt 0 ]]
veya [[ -n $(... | head -c1) ]]
daha iyidir çünkü wc -c
komutun tüm çıktısını tüketmek zorunda kalacaktır.
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
Bu, komutu çalıştıracak ve döndürülen çıktının (dize) sıfır uzunlukta olup olmadığını kontrol edecektir. Diğer bayraklar için 'test' kılavuz sayfalarını kontrol etmek isteyebilirsiniz .
Kontrol edilen bağımsız değişkenin etrafında "" kullanın, aksi takdirde boş sonuçlar (denetlenecek) ikinci bir bağımsız değişken olmadığından bir sözdizimi hatasına neden olur!
Not: Bu ls -la
hep döner .
ve ..
böylece olmaz çalışması sonuçlarını kullanarak bkz ls manuel sayfaları . Dahası, bu rahat ve kolay görünse de, kolayca kırılacağını düşünüyorum. Sonuca bağlı olarak 0 veya 1 döndüren küçük bir komut dosyası / uygulama yazmak çok daha güvenilirdir!
$(
$(
Zarif, bash sürümünden bağımsız bir çözüm isteyenler (aslında diğer modern kabuklarda çalışmalıdır) ve hızlı görevler için tek astar kullanmayı sevenler için. İşte başlıyoruz!
ls | grep . && echo 'files found' || echo 'files not found'
(bahsedilen yorumlardan biri olarak not edin ls -al
ve aslında, sadece -l
ve -a
hepsi bir şey döndürecek, bu yüzden cevabımda basit kullanıyorumls
grep -q ^
bunun yerine, yeni satır karakterleri de eşleştirilecek ve grep standart çıkışa şey yazdırmaz. Ayrıca, giriş akışının bitmesini beklemek yerine herhangi bir girdi alır almaz çıkacaktır.
ls -A
Eğer dosyaları nokta (veya dizinleri) eklemek istiyorsanız
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
Steno versiyonunu kullanabilirsiniz:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
string
bir eşanlamlı olduğunu görürsünüz -n string
.
Jon Lin'in yorumladığı gibi, ls -al
her zaman çıktı için ( .
ve ..
). ls -Al
Bu iki dizinden kaçınmak istiyorsunuz .
Örneğin, komutun çıktısını bir kabuk değişkenine koyabilirsiniz:
v=$(ls -Al)
Daha eski, tartışılamaz bir gösterim
v=`ls -Al`
ama seçilebilir gösterimi tercih ederim $(
...)
Bu değişkenin boş olup olmadığını test edebilirsiniz
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
Ve her ikisini de if [ -n "$(ls -Al)" ]; then
ls -al
Komutun çıktısını istediğinizi tahmin ediyorum , bu yüzden bash'da şöyle bir şey olurdu:
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi
ls
hiçbir zaman yürütülmez. Yalnızca değişkenin genişlemesinin LS
boş olup olmadığını kontrol edersiniz .
-a
Anahtar (orada dosyalardır olsun veya olmasın yani o içeriği döndürür) her zaman örtük olmadığı için hiçbir içeriği döndürür asla .
ve ..
dizinleri mevcut.
Şimdiye kadar verilen tüm cevaplar boş olmayan bir dizeyi sonlandıran ve çıktı veren komutlarla ilgilidir .
Çoğu aşağıdaki duyularda kırılır:
yes
).Tüm bu sorunları gidermek ve aşağıdaki soruyu verimli bir şekilde cevaplamak için,
Bir komutun boş bir dize çıkıp çıkmadığını nasıl sınayabilirim?
kullanabilirsiniz:
if read -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Komutun read
' -t
seçeneğini kullanarak belirli bir süre içinde boş olmayan bir dize çıkıp çıkmadığını sınamak için biraz zaman aşımı da ekleyebilirsiniz . Örneğin, 2,5 saniyelik bir zaman aşımı için:
if read -t2.5 -n1 -d '' < <(command_here); then
echo "Command outputs something"
else
echo "Command doesn't output anything"
fi
Remark. Bir komutun boş olmayan bir dize çıkıp çıkmadığını belirlemeniz gerektiğini düşünüyorsanız, büyük olasılıkla bir XY sorununuz vardır.
seq 1 10000000
, seq 1 20
ve printf""
). Bu okuma yaklaşımının kazanamadığı tek eşleşme -z "$(command)"
, boş bir girdi yaklaşımıydı. O zaman bile, sadece yaklaşık% 10-15 oranında kaybeder. Etrafta kırılıyor gibi görünüyorlar seq 1 10
. Ne olursa olsun, giriş boyutu büyüdükçe -z "$(command)"
yaklaşım o kadar yavaş olur ki , herhangi bir değişken boyutlu giriş için kullanmaktan kaçınırdım.
İşte bazı komutların std-out ve std-err'lerini geçici bir dosyaya yazan ve daha sonra bu dosyanın boş olup olmadığını kontrol eden alternatif bir yaklaşım. Bu yaklaşımın bir yararı, her iki çıkışı da yakalaması ve alt kabuklar veya borular kullanmamasıdır. Bu son hususlar önemlidir, çünkü yakalama bash çıkış işlemesine müdahale edebilirler (örneğin burada )
tmpfile=$(mktemp)
some-command &> "$tmpfile"
if [[ $? != 0 ]]; then
echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
echo "Command generated output"
else
echo "Command has no output"
fi
rm -f "$tmpfile"
Bazen çıktıyı, boş değilse, başka bir komuta geçirmek için kaydetmek istersiniz. Eğer öyleyse,
list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
/bin/rm $list
fi
Bu şekilde, rm
liste boşsa komut askıda kalmaz.