Bul komutundan alınan dosya adını değiştirme


10

Bash için nispeten yeniyim ve yüzeyde oldukça basit görünen bir şey yapmaya çalışıyorum - tüm * .wma dosyalarını almak için bir dizin hiyerarşisi üzerinde çalışın, onları mp3'e dönüştürdüğüm bir komuta boru ve dönüştürülen dosyayı .mp3 kaydedin. Benim düşüncem, komutun aşağıdaki gibi görünmesi gerektiğiydi (Ses dönüştürme komutunu bıraktım ve bunun yerine illüstrasyon için yankı kullanıyorum):

$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3

Anladığım kadarıyla, -print0 arg alanı olan dosya adlarını (bunların çoğunun müzik dosyası olduğu gibi) kullanmama izin verecek. Daha sonra (xargs sonucunda) bulmak her dosya yolu f yakalanan ve alt dize kullanarak / dizenin sonundan silmek silmek, ben bir mp3 ile orijinal dosya yolunu yankılanmasını bekliyorum wma yerine uzantı. Ancak, bu sonuç yerine, aşağıdakileri görüyorum:

*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...

Yani sorum (belirli 'burada neyi yanlış yapıyorum' dışında), bu - bir boru işleminin sonucu olan değerlerin, dize manipülasyon işlemlerinde değişken bir atamanın sonucu olanlardan farklı şekilde ele alınması gerekir. ?


1
Kullanmak için hiçbir neden yoktur xargsile find. Bir -execseçenek ile geliyor . Sadece kullanacağınız komutu sorunuza ekleyebilir misiniz ve birisi size doğru findkomutu gösterebilir mi ?
ixtmixilix

evet (aşağıda belirttiğim gibi), hala find komutunun her sonucunda dize manipülasyonu yapabildiğim sürece (örn. {}üye)
Howard Dierking

aslında xargsdaha uygun olan kenar durumlar vardır exec. Bu vaka için stackoverflow.com/questions/896808/find-exec-cmd-vs-xargs bu yığın dizisine bakın .
d34dh0r53

@ d34dh0r53 Hangi kenar durumu? Bağlantı verdiğiniz konuya işaret etmiyor.
Gilles 'SO- kötü olmayı bırak'

Yanıtlar:


8

Diğer cevaplar zaten tanımlandığı gibi, komutu ${f%.*}çalıştırmadan önce kabuk tarafından genişletilir xargs. Bu genişletmenin her dosya adı için bir kez gerçekleşmesi gerekir, kabuk değişkeni fdosya adına ayarlanır (iletme -I fbunu yapmaz: xargskabuk değişkeni kavramı yoktur f, komutta dizeyi arar. kullanılan örneğin xargs -I e echo …neye komutları idam olurdu ./somedir/somefile.wmacho .mp3).

Bu yaklaşımı xargssürdürerek, genişlemeyi gerçekleştirebilecek bir kabuk çağırmayı söyleyin . Daha iyi, söyle find- xargsbüyük ölçüde eski bir araçtır ve modern buluntu versiyonları, daha az sıhhi tesisat zorluğu ile aynı işi (ve daha fazlasını) yapan bir yapıya sahip olduğundan, doğru bir şekilde kullanılması zordur. Bunun yerine find … -print0 | xargs -0 command …koş find … -exec command … {} +.

find . -name '*.wma' -type f -exec sh -c 'for f; do echo "${f%.*}.mp3"; done' _ {} +

Bağımsız değişken _olan $0kabuk; dosya adları, üzerinden geçen konumsal bağımsız değişkenler olarak iletilir for f; do …. Bu komutun daha basit bir sürümü, her dosya için eşdeğer ancak biraz daha yavaş olan ayrı bir kabuk yürütür:

find . -name '*.wma' -type f -exec sh -c 'echo "${0%.*}.mp3"' {} \;

findMakul bir zamanda yeni bir kabuk (ksh93, bash ≥4.0 veya zsh) çalıştırdığınızı varsayarak burada kullanmanıza gerek yoktur . Bash olarak koymak shopt -s globstarGözlerinde farklı .bashrcetkinleştirmek için **/(ksh en o Altdizinlerde recurse için glob desen set -o globstar). Sonra koşabilirsin

for f in **/*.wma; do
  echo "${f%.*}.mp3"
done

(Dizini çağırdıysanız *.wma, [ -f "$f" ] || continuedöngünün başına ekleyin .)


harika açıklamalar da fark etmediğim bir yöne işaret etti (globtar işlevselliği elde etmek için bash kabuğumu yükseltme) - sonunda, yinelemeli globbing komutu basit tutan ve yapmaya çalıştığım her şeyi başaran çözümdü . Teşekkürler!
Howard Dierking

6

Çözümü değerlendirmeniz durumunda $ {f%. *}. Mp3, xargs tarafından çatallanan kabukta değil, tüm komutu çağırdığınız kabukta yapılır . Ve kabuğunuzda f değişkeni yoktur , boş bir dize ile değiştirilir.

-I f ile xargs kullanan çözüm :

% cat 1.sh 
#!/bin/sh
f=$1
echo ${f%.*}.mp3
% /bin/ls -1
1.sh
aaa.wma
bbbb.wma
ccccc.wma
% find ./ -name '*.wma' -type f -print0 | xargs -0 -I f ./1.sh f
./aaa.mp3
./ccccc.mp3
./bbbb.mp3

Ama bunu şu şekilde yaparım:

% find ./ -name '*.wma' -type f | sed 's,\.wma$,.mp3,'
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.