Jak odstranit příponu názvu souboru ze seznamu názvů souborů v bash

Pokouším se odstranit příponu názvu souboru ze seznamu souborů, které jsem vygeneroval pomocí následujícího bash skript:

 #!/bin/bash file_list=$(find . -type f) #assuming that the files are stored in the same directory trimmed_file_list=$(printf "%s\n" "${file_list[@]%.*}") printf "%s\n" "${trimmed_file_list[@]}" 

Tato expanze ořezá příponu mimo poslední položku v seznamu, ale ne některou z dřívějších.

Například chci následující seznam:

 file1.pdf file2.pdf file3.png 

Stát se

 file1 file2 file3 

Ale místo toho dostanu:

 file1.pdf file2.pdf file3 

Raději to nedělám ve smyčce, chtěl bych použít rozšíření parametrů. Chci se vyhnout řezání, protože chci odstranit pouze poslední příponu ze souboru.

Existuje několik témat o rozšiřování parametrů a zdá se, že bash se může dusit … opravdu si nejsem jistý. Pokud tento problém vysvětlí jiné z již existujících témat, nechápu, o co jde.

Témata, která se zdají související, ale zdá se, že můj problém nevyřeší:

Komentáře

  • Váš název uvádí pole, ale v kódu není žádné pole.
  • @Kusalananda Děkuji! Od dotazu jsem si to ' uvědomil. Stále se učím 🙂
  • @Kusalananda Pokračoval jsem ' a upravil otázku tak, aby lépe odpovídala problému. To by mělo zabránit tomu, aby se na stránku dostalo chybné vyhledávání google. Děkujeme za informace!

Odpověď

Dalo by se vše v jednom příkazu.

find /path/to -type f -execdir bash -c "printf "%s\n" "${@%.*}"" bash {} + 

Komentáře

  • Děkuji! Vlastně potřebuji vytvořit pár kopií pole, jednu pro nabídku, která má upravený název souboru a druhou, která si zachová původní hodnotu indexu, abych mohl zavolat soubor z nabídky. Je opravdu úžasné, kolik bash dokáže! Schopnost vložit vše do jednoho příkazu mě stále odvádí pryč! : D

Odpověď

Věřím, že byste místo řetězce chtěli vytvořit pole:

IFS=$"\n" # split on newline only set -o noglob # disable the glob part file_list=($(find . -name "*.*" -type f)) 

Nebo s bash 4.4+, aniž by se narušily cesty k souborům pomocí znaků nového řádku:

readarray -td "" file_list < <(find . -name "*.*" -type f -print0) 

Pak by rozšíření vašich parametrů mělo fungovat, i když zde by mělo smysl znovu použít proměnnou pole:

trimmed_file_list=("${file_list[@]%.*}") 

Ve svém ukázkovém kódu vytváříte řetězec poté požádejte o rozšíření parametrů, aby odstranilo vše za posledním tečkovým znakem v celém řetězci.

Komentáře

  • Děkuji! Otestuji to, jakmile ráno narazím na stůl.
  • Předpokládá se, že žádné názvy souborů v tomto adresáři neobsahují mezery nebo znaky s globusy.
  • @Wildcard, by měl být adresováno poslední úpravou.
  • @Wildcard Děkujeme za ukazatel! ' generuji soubory, které jsou do tohoto adresáře vloženy programově, takže by to nemělo být ' problém.

Odpověď

Váš kód neobsahuje žádná pole. Také vloží seznam názvů souborů do řetězce $file_list. Obsah řetězce končí řetězcem file3.png a nahrazení parametrů odstraní řetězec .png a ponechá vám jediný řetězec názvů souborů, kde poslední název souboru nemá příponu názvu souboru.

Vložení více samostatných objektů (názvů cest) do jednoho řetězce automaticky diskvalifikuje správnou funkci skriptu u souborů, jejichž názvy obsahují mezery (nebo jakýkoli oddělovač, který řetězec používá). Použití pole by nepomohlo, protože byste stále rozdělili výstup find na bílé mezery.


Oříznutí přípony všech názvů běžných souborů v aktuálním adresáři nebo pod ním:

find . -type f -name "*.*" -exec sh -c " for pathname do printf "Would move %s to %s...\n" "$pathname" "${pathname%.*}" # mv -i "$pathname" "${pathname%.*}" done" sh {} + 

Hledá běžné soubory, jejichž názvy obsahují alespoň jednu tečku. Názvy cest k těmto souborům se dávkově dávkují do malého skriptu prostředí, který se nad nimi smyčí. Shell skript přejmenuje soubory odstraněním poslední tečky v názvu souboru a všeho, co následuje. Skutečný příkaz mv je z důvodu bezpečnosti komentován.

Příkaz find slouží jako generátor názvů cest pro skript interního prostředí a je zaručeno, že budeme správně zpracovávat názvy cest obsahující mezery, nové řádky a karty. Není nutné ukládat výstupy příkazů do proměnných.

Pokud máte řadu názvů cest, případně vytvořených pomocí

shopt -s globstar nullglob file_list=( **/*.* ) # get pathnames of files with dots in their names 

Pak byste byli schopni vydat názvy cest bez přípon s

printf "%s\n" "${file_list[@]%.*}" 

Zda by vám to pomohlo, nevím. Pokud chcete použít názvy cest bez přípon pro něco , pak by použití výstupu výše uvedeného printf příkazu bylo špatnou věcí (vrátili byste se, když už nezpracováváte cizí cestu). Takže když a jak odstraníte přípony názvu souboru, záleží na tom, co byste chtěli s výsledkem udělat.

Související:

Komentáře

  • Děkujeme! Vaše zvládnutí bash je velmi evidentní! ' stále škrábám na povrchu … Děkuji, že jste si našli čas a pomohli 🙂

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *