Gibi bir dize dosyası yolu göz önüne alındığında , söz konusu dizenin /foo/fizzbuzz.bar
sadece bir fizzbuzz
kısmını ayıklamak için bash'ı nasıl kullanırım ?
Gibi bir dize dosyası yolu göz önüne alındığında , söz konusu dizenin /foo/fizzbuzz.bar
sadece bir fizzbuzz
kısmını ayıklamak için bash'ı nasıl kullanırım ?
Yanıtlar:
Bash içindeki # ve% operatörleriyle nasıl yapılacağı aşağıda açıklanmıştır.
$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz
${x%.bar}
Ayrıca olabilir ${x%.*}
bir nokta sonra her şeyi kaldırmak veya ${x%%.*}
ilk noktasından sonraki her şeyi kaldırın.
Misal:
$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz
Belgeleri Bash kılavuzunda bulabilirsiniz . Bak ${parameter%word}
ve ${parameter%%word}
kısım uygun bölümü arka.
basename komutuna bakın:
NAME="$(basename /foo/fizzbuzz.bar .bar)"
Basename kullanarak bunu başarmak için aşağıdakileri kullandım:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
Bu, dosya uzantısı hakkında önceden bilgi gerektirmez ve dosya adında (uzantısının önünde) noktalara sahip bir dosya adınız olsa bile çalışır; basename
Yine de program gerektiriyor , ancak bu GNU coreutils'in bir parçası olduğu için herhangi bir dağıtımla birlikte gönderilmelidir.
fname=`basename $file .$ext`
Saf bash yolu:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
Bu işlevsellik insan bashında "Parameter Expansion" altında açıklanmaktadır. Bash olmayan yollar boldur: awk, perl, sed vb.
DÜZENLEME: Dosya soneklerindeki noktalarla çalışır ve soneki (uzantı) bilmesine gerek yoktur , ancak adın kendisindeki noktalarla çalışmaz .
Taban adı ve dizin adı işlevleri peşinde olduğunuz şeydir:
mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")
Çıktı var:
basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo
mystring=$1
ve adres sorunları o (boşluk / glob karakterleri / vs içeren değil belli olan birkaç uyarı bastırmak olacaktır) yerine geçerli sabit değer bulur?
echo "basename: $(basename "$mystring")"
eğer bu şekilde - mystring='/foo/*'
sen alamadım *
geçerli dizinde dosyaların listesini ile değiştirilir sonra basename
bittikten.
Kullanılması basename
o, dosya uzantısı olduğunu biliyorum gelmez varsayar?
Ve çeşitli düzenli ifade önerilerinin birden fazla "" içeren bir dosya adıyla baş etmediğine inanıyorum.
Aşağıdaki çift nokta ile başa çıkmak gibi görünüyor. Oh ve kendileri "/" içeren dosya adları (sadece tekmeler için)
Pascal'ı açıklamak için, "Üzgünüm, bu senaryo çok uzun. Daha kısa yapmak için zamanım yoktu"
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
Bu cevapta kullanılan POSIX uyumlu sözdizimine ek olarak ,
basename string [suffix]
de olduğu gibi
basename /foo/fizzbuzz.bar .bar
GNUbasename
başka bir sözdizimini destekler:
basename -s .bar /foo/fizzbuzz.bar
aynı sonucu verir. Fark ve avantaj, birden fazla argümanı destekleyen şu -s
anlama gelir -a
:
$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar
Bu, -z
örneğin boşluklar, yeni satırlar ve glob karakterleri (alıntılanan ls
) içeren dosyalar için , seçeneği kullanarak çıktıyı NUL baytlarıyla ayırarak dosya adı açısından güvenli hale getirilebilir :
$ ls has*
'has'$'\n''newline.bar' 'has space.bar' 'has*.bar'
Bir diziye okuma:
$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")
readarray -d
Bash 4.4 veya daha yenisini gerektirir. Daha eski sürümler için:
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
perl -pe 's/\..*$//;s{^.*/}{}'
Basename'i diğer yayınlarda önerildiği gibi kullanamıyorsanız, her zaman sed kullanabilirsiniz. İşte (çirkin) bir örnek. En büyük değil, ancak istenen dizeyi ayıklayarak ve girdiyi istenen dizeyle değiştirerek çalışır.
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
Hangi çıktıyı alacak
fizzbuzz
Önerilen perl çözümüne dikkat edin: ilk noktadan sonra her şeyi kaldırır.
$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some
Perl ile yapmak istiyorsanız, bu işe yarar:
$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with
Ancak Bash kullanıyorsanız, y=${x%.*}
(veya basename "$x" .ext
uzantıyı biliyorsanız) ile çözümler çok daha basittir.
Taban adı bunu yapar, yolu kaldırır. Ayrıca, sonek verilirse ve dosyanın sonekiyle eşleşirse kaldırır, ancak komuta vermek için son eki bilmeniz gerekir. Aksi takdirde mv'yi kullanabilir ve yeni adın başka ne olması gerektiğini anlayabilirsiniz.
Tam yolu kullanmadan dosya adını almak için en yüksek puanlı cevabı ikinci en yüksek puanlı cevapla birleştirmek:
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
${parameter%word}
ve${parameter%%word}
porsiyon eşleştirme bölümüne sondaki içinde.