Kabuk: Bir dizenin belirtilen bir karakteri [yinelenen] içerip içermediğini kontrol etme
#!/bin/sh
TMP=$(cd Folder && ls) for name in $TMP; do
if [[ "${name}" != *"a"* -a ${name} == *"b"* ]] ;then
echo $name
fi
done
İçinde 'a' olmayan ama onun yerine 'b' olan isimleri çıkarmaya çalışıyordum. Aldığım hata bu:
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
Burada neyi yanlış yapıyorum?
Yanıtlar
Ana sorununuz, bu tür testleri desteklemeyen [[ ... ]]
bir komut dosyasında bir model eşleştirmesi kullanmanızdır /bin/sh
. Ayrıca, bir sh dosyasından çalıştırıldığında, Kabuk betiği, bulunamadı hatası atıyor başlıklı soruya bakın . Ancak manuel olarak girilirse komutlar çalışır
Diğer sorun ise, çıktısını ls
boşluklar, sekmeler ve satırsonları üzerindeki kelimelere ayırmadan önce tek bir dizede birleştirmeniz ve oluşturulan kelimelere dosya adı globbing uygulamanızdır. Daha sonra bunun sonucunun üzerinden geçersiniz.
Yerine:
#!/bin/sh
cd Folder || exit 1
for name in *b*; do
[ -e "$name" ] || [ -L "$name" ] || continue
case $name in (*a*) ;; (*) printf '%s\n' "$name"; esac
done
Bu, Folder
dizindeki içinde harf b
bulunan tüm dosyalar üzerinde döngü yapar ve sonra bunlardan a
. a
Karakterin testi kullanılarak yapılır case ... esac
. *a*
Desen bir maçları a
vaka hiçbir şey olmuyor ki, eğer varsa dosya adını karakter. printf
İfadeleri hiçbir yoksa işletilirse, "varsayılan" durumda olduğu a
dizesinde.
Döngü deseninin hiçbir şeyle eşleşmediği uç durumu yakaladığımızdan emin olmak için -e
ve ile yapılan testler -L
var. Bu durumda, model genişletilmemiş olarak kalacaktır, bu nedenle genişletilmemiş bir model ile mevcut bir dosya arasında ayrım yapabildiğimizden emin olmak için test ederiz -e
. -L
Test döngü deseni ile aynı ada sahip bir sembolik bağın daha da kenar durumda yakalamak, ama bu her yerde geçerli işaret etmez. Aşağıdaki bash
kodun buna ihtiyacı yoktur çünkü onun nullglob
yerine kabuk seçeneğini kullanır (içinde mevcut değildir /bin/sh
).
Döngünün çıktılar *b*
yerine örgünün genişletilmesi üzerinden çalıştırılması, bunun ls
aynı zamanda boşluklar, sekmeler, satırsonları ve dosya adı genelleme karakterleri içeren dosya adlarıyla da başa çıkabilme avantajına sahiptir (dosya adları asla daha sonra denediğimiz tek bir dizeye yerleştirilmez) tekrar tekrar).
In bash
kabuk, bir ile aynı yapabileceğini [[ ... ]]
kendiniz yapmaya çalıştık gibi, desen eşleştirme testi:
#!/bin/bash
cd Folder || exit 1
shopt -s nullglob
for name in *b*; do
[[ $name != *a* ]] && printf '%s\n' "$name"
done
Ayrıca bakınız:
- Kabuk betiğim neden boşlukta veya diğer özel karakterlerde boğuluyor?
- Çift tırnak ne zaman gereklidir?
- "Ls" yi neden * çözümlemiyor * (ve bunun yerine ne yapmalı)?
- Printf neden echo'dan daha iyidir?
Dosya adlarını yazdırmak için Folder
içermez b
ve a
içinde zsh
ve onun ~
( hariç / ve-olmayan ) glob operatörü:
#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)
(kaldırmak N
için ( nullglob
Bunun yerine eşleşen dosya olduğu yerde bir hata bildirilebilir istediğimiz ise).
In ksh93
(bu [[...]]
operatörü (standart sh
sözdiziminin parçası olmayan ) ve &
( ve ) ve !(...)
( değil ) operatörlerini tanıtan kabuk :
#! /bin/ksh93 -
(
CDPATH= cd Folder &&
set -- ~(N)@(*b*&!(*a*)) &&
(($# > 0)) && printf '%s\n' "$@"
)
İle bash
(ister kabuk zsh
ayrıca Ksh en kopyaladıysa [[...]]
kullanarak operatörü), extglob
ksh88 glob operatörlerini desteklemek ve nullglob
zsh en etkisini elde etmek için N
glob eleme veya ksh93
'ın ~(N)
glob operatörü ve bazı çift olumsuzlamasıydı |
( veya elde etmek) ve :
#! /bin/bash -
(
shopt -s extglob nullglob
cd ./Folder &&
set -- !(!(*b*)|*a*) &&
(($# > 0)) && printf '%s\n' "$@"
)
Standart sh
sözdiziminde:
#! /bin/sh -
(
CDPATH= cd Folder || exit
set -- [*]b[*] *b*
[ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
# expands to itself because there's
# no match as there's no nullglob
# equivalent in sh
shift
for i do
case $i in (*a*) ;; (*) set -- "$@" "$i" esac shift done [ "$#" -gt 0 ] && printf '%s\n' "$@"
)
cd
Okuma erişiminiz varsa Folder
ancak arama erişiminiz yoksa , kullanılan çözümlerin çalışmayacağını unutmayın .
Daha genel olarak, bir dizenin başka bir dizge içerip içermediğinin nasıl kontrol edileceğine ilişkin genel soruyu yanıtlamak için sh
, en iyisi, içinde case
desen eşleştirmeyi nasıl yaptığınız yapıdadır sh
. Bir yardımcı işlev bile kullanabilirsiniz:
contains()
case "$1" in
(*"$2"*) true;;
(*) false;;
esac
Gibi kullanmak için:
if contains foobar o; then
echo foobar contains o
fi
if ! contains foobar z; then
echo foobar does not contain o
fi
if
contains "$file" b &&
! contains "$file" a then printf '%s\n' "$file contains b and not a "
fi