Ik probeer de bestandsnaamextensie te verwijderen uit een lijst met bestanden die ik heb gegenereerd met het volgende bash-script:
#!/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[@]}"
Deze uitbreiding trimt de extensie van het laatste item in de lijst, maar niet van de eerdere.
Ik wil bijvoorbeeld de volgende lijst:
file1.pdf file2.pdf file3.png
Om
file1 file2 file3
Maar in plaats daarvan krijg ik:
file1.pdf file2.pdf file3
Ik “doe dit liever niet in een lus, ik” zou graag parameteruitbreiding willen gebruiken. Ik wil knippen voorkomen, omdat ik alleen de laatste extensie in het bestand wil verwijderen.
Er zijn een behoorlijk aantal onderwerpen over parameteruitbreiding en het lijkt erop dat bash stikt in find
” gebruik van nieuwe regels … Ik weet het echt niet zeker. Als een van de reeds bestaande onderwerpen dit probleem uitlegt, begrijp ik niet helemaal wat er aan de hand is.
Onderwerpen die lijken gerelateerd, maar lijkt mijn probleem niet op te lossen:
- Hoe kan ik de extensie van een bestandsnaam in een shellscript verwijderen?
- Shell-parameteruitbreiding op arrays
- Bestandsnaam verwijderen extensies met find -exec
Reacties
- Uw titel vermeldt arrays, maar er is geen array in uw code.
- @Kusalananda Bedankt! Ik ‘ realiseer me dat sinds ik het heb gevraagd. Nog steeds aan het leren 🙂
- @Kusalananda Ik ‘ ben verder gegaan en heb de vraag aangepast zodat deze beter overeenkomt met het probleem. Dat zou moeten voorkomen dat foutieve Google-zoekopdrachten de pagina bereiken. Bedankt voor de informatie!
Antwoord
Je zou alles in één commando kunnen doen.
find /path/to -type f -execdir bash -c "printf "%s\n" "${@%.*}"" bash {} +
Reacties
- Bedankt! Ik moet eigenlijk een paar kopieën van de array maken, een voor een menu waarvan de bestandsnaam is gewijzigd en een die de oorspronkelijke indexwaarde behoudt, zodat ik het bestand vanuit het menu kan oproepen. Het is echt verbazingwekkend hoeveel bash kan doen! De mogelijkheid om alles in één commando in te bedden, blaast me nog steeds weg! : D
Answer
Ik denk dat je een array zou willen maken in plaats van een string:
IFS=$"\n" # split on newline only set -o noglob # disable the glob part file_list=($(find . -name "*.*" -type f))
Of met bash 4.4+, niet breken op bestandspaden met tekens voor nieuwe regels:
readarray -td "" file_list < <(find . -name "*.*" -type f -print0)
Dan zou uw parameteruitbreiding moeten werken, hoewel het hier logischer zou zijn om opnieuw een arrayvariabele te gebruiken:
trimmed_file_list=("${file_list[@]%.*}")
In uw codevoorbeeld maakt u een string en vervolgens parameteruitbreiding vragen om alles na het laatste punt-teken in de volledige string te verwijderen.
Opmerkingen
- Bedankt! Ik zal het testen zodra ik s ochtends op mijn bureau sta.
- Hierbij wordt ervan uitgegaan dat er geen bestandsnamen in die map witruimte of globbing-tekens bevatten.
- @Wildcard, zou moeten zijn geadresseerd door de laatste bewerking.
- @Wildcard Bedankt voor de aanwijzer! Ik ‘ m genereer de bestanden die programmatisch in deze directory worden geplaatst, dus het zou geen ‘ een probleem moeten zijn.
Answer
Uw code bevat geen arrays. Het plaatst ook een lijst met bestandsnamen in een string, $file_list
. De inhoud van de tekenreeks eindigt op file3.png
en uw parametervervanging verwijdert .png
uit de tekenreeks, waardoor u een enkele reeks bestandsnamen overhoudt waarin de laatste bestandsnaam heeft geen achtervoegsel voor de bestandsnaam.
Door meerdere afzonderlijke objecten (padnamen) in een enkele string te plaatsen, diskwalificeert het automatisch dat het script niet goed werkt voor bestanden waarvan de naam spaties bevat (of welk scheidingsteken de string ook gebruikt). Het gebruik van een array zou niet helpen, aangezien je de uitvoer van find
nog steeds zou splitsen in witruimten.
De extensie van alle bestandsnamen van reguliere bestanden knippen in of onder de huidige directory:
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 {} +
Dit zoekt naar gewone bestanden waarvan de naam minstens één punt bevat. De padnamen van deze bestanden worden in batches ingevoerd in een klein shell-script dat er overheen loopt. Het shellscript hernoemt de bestanden door de laatste punt in de bestandsnaam en alles wat daarna komt te verwijderen. Het eigenlijke mv
commando is voor de veiligheid voorzien van commentaar.
Het find
commando werkt als een generator van padnamen voor de interne shell-script, en we zijn er zeker van dat we padnamen met spaties, nieuwe regels en tabbladen correct verwerken. Het is niet nodig om de uitvoer van opdrachten in variabelen op te slaan.
Als je een reeks padnamen hebt, mogelijk gemaakt met behulp van
shopt -s globstar nullglob file_list=( **/*.* ) # get pathnames of files with dots in their names
Dan zou je de padnamen kunnen uitvoeren zonder achtervoegsels met
printf "%s\n" "${file_list[@]%.*}"
Of dit je zou helpen, ik weet het niet. Of je de padnamen gebruikt zonder achtervoegsels voor iets , dan zou het verkeerd zijn om de uitvoer van het bovenstaande printf
commando te gebruiken (je zou weer terug zijn in het niet meer omgaan met vreemde padnaam). en hoe u de achtervoegsels van de bestandsnaam verwijdert, hangt af van wat u met het resultaat wilt doen.
Gerelateerd:
Opmerkingen
- Bedankt! Je beheersing van bash is heel duidelijk! Ik ‘ schraap nog steeds aan de oppervlakte … Bedankt dat je de tijd hebt genomen om te helpen 🙂