Jag försöker ta bort filnamnstillägget från en lista med filer som jag har skapat med följande 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[@]}"
Denna expansion avklippar tillägget från sista posten i listan, men inte någon av de tidigare.
Till exempel vill jag ha följande lista:
file1.pdf file2.pdf file3.png
Att bli
file1 file2 file3
Men istället får jag:
file1.pdf file2.pdf file3
Jag föredrar att inte göra detta i en slinga, jag vill använda parameterutvidgning. Jag vill undvika klipp eftersom jag bara vill ta bort det sista tillägget i filen.
Det finns ett ganska stort antal ämnen om parameterutvidgning och det verkar som om bash kanske kväver på find
” s användning av nya rader … Jag är verkligen inte säker. Om ett annat av de befintliga ämnena förklarar problemet, förstår jag inte helt vad som händer.
Ämnen som verkar relaterat men verkar inte lösa mitt problem:
- Hur kan jag ta bort filnamnstillägget i ett skalskript?
- Skalparameterutvidgning på matriser
- Tappar filnamn tillägg med hitta -exec
Kommentarer
- Din titel nämner arrayer, men det finns ingen matris i din kod.
- @Kusalananda Tack! Jag ' har insett det sedan jag frågade. Lär dig fortfarande 🙂
- @Kusalananda Jag ' har gått vidare och ändrat frågan för att bättre matcha problemet. Det borde förhindra felaktiga google-sökningar från att träffa sidan. Tack för informationen!
Svar
Du kan göra allt i ett kommando.
find /path/to -type f -execdir bash -c "printf "%s\n" "${@%.*}"" bash {} +
Kommentarer
- Tack! Jag måste faktiskt skapa ett par kopior av matrisen, en för en meny där filnamnet har ändrats och en som behåller det ursprungliga indexvärdet så att jag kan ringa filen från menyn. Det är verkligen fantastiskt hur mycket bash kan göra! Förmågan att bädda in allt i ett kommando blåser mig fortfarande! : D
Svar
Jag tror att du vill skapa en matris istället för en sträng:
IFS=$"\n" # split on newline only set -o noglob # disable the glob part file_list=($(find . -name "*.*" -type f))
Eller med bash 4.4+, bryter inte på filvägar med nylinjetecken:
readarray -td "" file_list < <(find . -name "*.*" -type f -print0)
Då ska din parameterutvidgning fungera, men här vore det vettigare att använda en arrayvariabel igen:
trimmed_file_list=("${file_list[@]%.*}")
I ditt kodprov gör du en sträng fråga sedan parameterutvidgning om att ta bort allt efter det sista punkttecknet i hela strängen.
Kommentarer
- Tack! Jag testar det så snart jag träffar mitt skrivbord på morgonen.
- Detta förutsätter att inga filnamn i den katalogen innehåller något mellanslag eller globtecken.
- @Wildcard bör vara adresseras av den senaste redigeringen.
- @ Wildcard Tack för pekaren! Jag ' Jag genererar filerna som släpps in i den här katalogen programmatiskt så att det inte borde vara '.
Svar
Din kod innehåller inga matriser. Det sätter också en lista med filnamn i en sträng, $file_list
. Innehållet i strängen slutar med file3.png
och din parameterersättning tar bort .png
från strängen och lämnar dig med en enda sträng med filnamn där det sista filnamnet har inte ett filnamnssuffix.
Att sätta flera separata objekt (sökvägar) i en enda sträng diskvalificerar automatiskt att skriptet fungerar korrekt för filer vars namn innehåller mellanslag (eller vilken avgränsare strängen använder). Att använda en matris skulle inte hjälpa eftersom du fortfarande skulle dela utdata från find
på mellanslag.
Att klippa förlängningen av alla filnamn på vanliga filer. i eller under den aktuella katalogen:
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 {} +
Detta letar efter vanliga filer vars namn innehåller minst en punkt. Vägnamnen för dessa filer matas i satser i ett litet skalskript som slingrar sig över dem. Skalskriptet byter namn på filerna genom att ta bort den sista punkten i filnamnet och allt som kommer efter. Det faktiska mv
-kommandot kommenteras för säkerhets skull.
Kommandot find
fungerar som en generator för sökvägar för internt skalskript, och vi kommer garanterat att korrekt bearbeta sökvägar som innehåller mellanslag, nya rader och flikar. Det finns inget behov av att lagra utdata från kommandon i variabler.
Om du har en rad sökvägar, eventuellt skapade med hjälp av
shopt -s globstar nullglob file_list=( **/*.* ) # get pathnames of files with dots in their names
skulle du kunna skicka sökvägen utan suffix med
printf "%s\n" "${file_list[@]%.*}"
Huruvida detta skulle hjälpa dig vet jag inte. Om du vill använda sökvägen utan suffix för något , och sedan använda utdata från ovanstående printf
-kommando skulle det vara fel att göra (du skulle vara tillbaka när du inte hanterar konstigt sökväg igen). och hur du tar bort filnamnssuffixen beror på vad du vill göra med resultatet.
Relaterat:
Kommentarer
- Tack! Din behärskning av bash är mycket tydlig! Jag ' Skrapar fortfarande på ytan … Tack för att du tog dig tid att hjälpa till 🙂