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.