Bir kabuk komut dosyasında dosya adının uzantısını nasıl kaldırabilirim?


147

Aşağıdaki kodda sorun nedir?

name='$filename | cut -f1 -d'.''

Olduğu gibi, değişmez bir dize $filename | cut -f1 -d'.'alıyorum, ancak tırnakları kaldırırsam hiçbir şey alamıyorum. Bu arada, yazarak

"test.exe" | cut -f1 -d'.'

bir kabukta istediğim çıktıyı verir test,. Zaten $filenamedoğru değerin atandığını zaten biliyorum . Ne yapmak istiyorum uzantısı olmayan bir değişkene dosya adı atamaktır.


6
basename $filename .exeaynı şeyi yapardı. Bu, hangi uzantıyı kaldırmak istediğinizi her zaman bildiğinizi varsayar.
mpe

7
@mpe, yani basename "$filename" .exe. Aksi takdirde boşluklu dosya adları kötü haber olur.
Charles Duffy

Yanıtlar:


115

Komut değiştirme sözdizimini kullanıyor olmalısınız$(command) komut dosyası / komut bir komut çalıştırmak istediğinizde.

Yani hattın

name=$(echo "$filename" | cut -f 1 -d '.')

Kod açıklaması:

  1. echo değişkenin değerini al $filename ve standart çıktıya gönderir
  2. Daha sonra çıktıyı alıp cut komuta bağlarız
  3. cutKullanacaktır. ipi segmentlere kesmek için ayırıcı (ayırıcı olarak da bilinir) olarak ve -fçıktıda hangi segmentte olmasını istediğimizi seçeriz
  4. Sonra $()komut ikamesi çıktıyı alır ve değerini döndürür
  5. Döndürülen değer adlı değişkene atanır name

Bunun değişkenin ilk döneme kadar olan kısmını verdiğine dikkat edin .:

$ filename=hello.world
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello.hello.hello
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello
$ echo "$filename" | cut -f 1 -d '.'
hello

Teşekkürler. Ayrıca echo komutunu kullanmam gerektiğini fark ettim. name =echo $filename | cut -f1 -d'.'
mimicocotopus

17
Geri tepmeler POSIX tarafından kullanımdan kaldırılmıştır $(), tercih edilir.
jordanm

3
Birkaç karaktere ulaşmak için çatallama ve borular, akla gelebilecek en kötü çözümdür.
Jens

39
Bu cevabın problemi, giriş dizesinin SADECE bir noktaya sahip olduğunu varsaymasıdır ... @chepner'ın çok daha iyi bir çözümü var ... name = $ {dosyaadı%. *}
Scott Stensland

4
Bu cevap yeni başlayanların karakteristiğidir ve yayılmamalıdır. Chepner'ın cevabı
neric

261

Parametre genişletmeyi de kullanabilirsiniz:

$ filename=foo.txt
$ echo "${filename%.*}"
foo


1
Ve burada kullanmak üzereydim echo -n "This.File.Has.Periods.In.It.txt" | awk -F. '{$NF=""; print $0}' | tr ' ' '.' | rev | cut -c 2- | rev. Teşekkürler.
user208145

1
Bu, gibi birden fazla uzantıya sahip dosyalarla çalışır mı image.png.gz?
Hawker65

11
%.*yalnızca son uzantıyı kaldıracak; tüm uzantıları kaldırmak istiyorsanız kullanın %%.*.
chepner

1
Bu, kabul edilen cevaptan daha iyi çalışıyor gibi görünüyor. Yalnızca dosyada birden fazla nokta varsa son uzantıyı tıraş olurken kesim ilk noktadan sonra her şeyi kaldırır.
Dale Anderson


20

Dosya adınız bir nokta içeriyorsa (uzantının adı dışında) bunu kullanın:

echo $filename | rev | cut -f 2- -d '.' | rev

1
Orta devrimi unuttum, ama bir kez gördüm, bu harikaydı!
yüce Pooba

-sVerilen bir seçenekle daha da iyidir cut, böylece dosya adı nokta içermediğinde boş bir dize döndürür.
Hibou57

1
Bu, bence kabul edilen cevap olmalı, çünkü içlerindeki noktalarla, bir nokta ile başlayan gizli dosyalarla veya hatta birden fazla uzantıya sahip dosyayla çalışmaktadır.
Tim Krief

20
file1=/tmp/main.one.two.sh
t=$(basename "$file1")                        # output is main.one.two.sh
name=$(echo "$file1" | sed -e 's/\.[^.]*$//') # output is /tmp/main.one.two
name=$(echo "$t" | sed -e 's/\.[^.]*$//')     # output is main.one.two

istediğinizi kullanın. Burada son .(nokta) ve ardından metin uzantısı olduğunu varsayıyorum .


6
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}

çıktılar:

/tmp/foo.bar.gz /tmp/foo.bar

Yalnızca son uzantının kaldırıldığını unutmayın.


3

Benim tavsiyem kullanmak basename.
Varsayılan olarak Ubuntu'da, görsel olarak basit bir koddur ve vakaların çoğuyla ilgilenir.

Boşluklar ve çok noktalı / alt uzantı ile ilgili bazı alt durumlar şunlardır:

pathfile="../space fld/space -file.tar.gz"
echo ${pathfile//+(*\/|.*)}

Genellikle ilk gelen uzatma kurtulmak ., ama bizim başarısız ..yolu

echo **"$(basename "${pathfile%.*}")"**  
space -file.tar     # I believe we needed exatly that

İşte önemli bir not:

Boşluklarla başa çıkmak için çift tırnak içinde çift tırnak kullandım. Tek fiyat teklifi, $ yazarak iletilmeyecek. Bash alışılmadık ve genişleme nedeniyle "ikinci" ilk "tırnak" okuyor.

Ancak, hala düşünmeniz gerekir .hidden_files

hidden="~/.bashrc"
echo "$(basename "${hidden%.*}")"  # will produce "~" !!!  

beklenen sonuç değil. Bunu yapmak için $HOMEveya /home/user_path/
tekrar bash "olağandışı" olduğundan ve "~" genişletmeyin (bash BashPitfalls araması yapın)

hidden2="$HOME/.bashrc" ;  echo '$(basename "${pathfile%.*}")'

1
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"

çıktılar:

program

Bu Steven Penny'nin 3 yıl önce verdiği cevaptan ne farkı var?
gniourf_gniourf

1

Chepner cevabının yorumunda Hawker65 tarafından belirtildiği gibi, en çok oy alan çözüm ne birden fazla uzantıya (dosyaadı.tar.gz gibi) ne de yolun geri kalanındaki noktalara (this.path / ile .dots / in.path.name). Olası bir çözüm:

a=this.path/with.dots/in.path.name/filename.tar.gz
echo $(dirname $a)/$(basename $a | cut -d. -f1)

Bu, dosya adındaki bir yolun ilk sayımından önce yolu saymayan karakterleri seçerek "tar.gz" yi çıkarır. Muhtemelen biri uzantıları bu şekilde çıkarmak istemez.
Frotz

0

Kodunuzla ilgili iki sorun:

  1. Değişkende saklamak istediğiniz dizeyi oluşturan komutları çevrelemek için `(geri işaret) yerine '(işaret) kullandınız.
  2. "$ Filename" değişkenini boruya "cut" komutuna "echo" etmediniz.

Kodunuzu "name =` echo $ dosyaadı | cut -f 1 -d 'olarak değiştirirdim. ``, aşağıda gösterildiği gibi (yine, ad değişkeni tanımını çevreleyen arka kenelere dikkat edin):

$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$> 
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.