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ší:
- Jak mohu odstranit příponu názvu souboru ve skriptu prostředí?
- Rozšíření parametrů shellu na pole
- Zrušení názvu souboru rozšíření s find -exec
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 🙂