' ls -1 ': bestandsnamen weergeven zonder extensie

ls -1 somt mijn elementen als volgt op:

foo.png bar.png foobar.png ... 

Ik wil dat het wordt vermeld zonder de .png zoals:

foo bar foobar ... 

(de map bevat alleen .png bestanden)

Kan iemand me vertellen hoe ik grep in dit geval moet gebruiken?

Doel: ik heb een tekstbestand waarin alle namen worden vermeld zonder de uitbreiding. Ik wil een script maken dat het tekstbestand vergelijkt met de map om te zien welk bestand ontbreekt.

Opmerkingen

  • Je wilt voorzichtig zijn met een verzoek als dit. Linux heeft geen bestandsnaamextensies. Linux heeft bestandsnamen die al dan niet een . bevatten. Hoewel de conventie zegt dat je je bestanden een naam moet geven met .png aan het einde, is er geen reden waarom ik ‘ geen png-bestand kan hebben met de naam foo.zip of my.picture.20160518 of gewoon mypic.
  • @hymie I weet je, maar mijn elementen in die map hebben allemaal de naam .png aan het einde.
  • Wat is ‘ is een ” extensie “? Dat ‘ maakt geen deel uit van de naamgeving van Unix-bestanden; het ‘ s overdracht van VMS / NT / Windows wat dan ook. En jullie jongeren gaan ook van mijn gazon af. 🙂
  • Laat ‘ dit niet overdrijven. Het besturingssysteem behandelt extensies gewoon als onderdeel van de bestandsnaam, maar veel Unix-programmas besteden er aandacht aan, van de compiler tot de GUI. Het concept is zeker niet vreemd aan Unix.
  • Meestal wordt aangeraden te vermijden om de uitvoer van ls en om de output van ls en find door te sluizen, voornamelijk vanwege de mogelijkheid om newline,` tab char in de bestandsnaam. Als de bestandsnaam The new art of working on .png\NEWLINE files and other formats is, zullen veel van de voorgestelde oplossingen problemen veroorzaken.

Antwoord

Je hebt alleen de shell nodig voor deze job.

POSIXly:

for f in *.png; do printf "%s\n" "${f%.png}" done 

Met zsh:

print -rl -- *.png(:r) 

Reacties

  • Daar ‘ s printf niet nodig; echo ${f%.png} is voldoende.
  • @Conrad: echo gebruiken won ‘ t werkt in sommige gevallen niet goed, als de bestandsnaam beginnen met een streepje of bevatten reeksen met ontsnapping.
  • @DavidConrad: zie ook unix.stackexchange.com/a/65819/38906
  • @DavidConrad Bovendien geloof ik dat printf is ingebouwd, net als echo, iemand corrigeert me als ik ‘ m fout ben

Answer

ls -1 | sed -e "s/\.png$//" 

Het sed commando verwijdert (dat wil zeggen, het vervangt door de lege tekenreeks) een willekeurige tekenreeks .png gevonden aan het einde van een bestandsnaam.

De . wordt geëscaped als \. zodat het wordt geïnterpreteerd door sed als een letterlijk . teken in plaats van de regexp . (wat betekent dat aracter). De $ is het end-of-line anker, dus het “komt niet overeen met .png in het midden van een bestandsnaam.

Reacties

  • Ik denk dat het OP wil dat elke extensie verwijderd wordt, maar waarschijnlijk alleen de ” laatste “. Dus misschien verander je je anders goede antwoord met: sed 's/\.[^.]*$//'
  • ja, die regexp zou werk in dat geval … maar als het OP dat wil, moeten ze dat zeggen in plaats van specifiek te zeggen dat ze ” willen dat het wordt vermeld zonder de .png ”
  • De -1 is niet nodig, aangezien dit hier de standaard is.
  • @jlliagre Ik ben het met cas eens dat de -1 moet worden gespecificeerd. Het ‘ is alleen de standaardinstelling wanneer de pijp is ingeschakeld, wat voor sommigen een verborgen verrassing is. Dus het expliciet maken helpt Ik doe dit ook in mijn scripts, dus ik weet wat voor soort o utput I ‘ m verwacht.
  • Waarschuwing In het geval van een bestandsnaam met de sleutel (.png) voor een newline-teken zal je zelfs dat .png wissen en niet alleen de laatste. Het is beter om te vermijden om de uitvoer van ls door te sluizen en te ontleden, het reserveert vaak goed verborgen verrassingen … (enkele woorden en verwijzingen meer in het antwoord).

Antwoord

Als je alleen bash wilt gebruiken:

for i in *; do echo "${i%.png}"; done 

Je moet naar grep reiken wanneer je overeenkomsten probeert te vinden, niet om die sed te verwijderen / te vervangen. geschikter:

find . -maxdepth 1 -name "*.png" | sed "s/\.png$//" 

Als je eenmaal hebt besloten dat je een aantal submappen moet maken om je PNG-bestanden te ordenen, kun je dat gemakkelijk wijzigen in:

find . -name "*.png" | sed "s/\.png$//" 

Reacties

  • ls -1 | sed ‘ s / .png // ‘ werkt prima. Bedankt!
  • De find doorgesluisd naar sed oplossing kan enkele problemen opleveren als je vindt een bestand met de sleutel (.png) als een deel van de naam en net voor een teken voor een nieuwe regel. Het is beter om te vermijden om de uitvoer van find of ls door te sluizen en te ontleden, het reserveert vaak goed verborgen verrassingen … (enkele woorden en meer verwijzingen in het antwoord).
  • Vervang waarschijnlijk find door iets als echo in het laatste voorbeeld. Het is niet duidelijk welk doel find daar dient en de resultaten zijn afhankelijk van de directorystructuur (bijv. Of u een directory files.png)
  • @BroSlow Bijgewerkt naar iets zinnigs.

Antwoord

Nog een zeer vergelijkbaar antwoord (ik ben verrast bepaalde variant is nog niet “t verschenen) is:

ls | sed -n "s/\.png$//p" 
  • Je hebt de -1 niet nodig optie naar ls, aangezien ls ervan uitgaat dat als de standaarduitvoer niet “ta terminal is (het is in dit geval een pijp).
  • de -n optie naar sed betekent de regel niet standaard afdrukken
  • de /p optie aan het einde van de vervanging betekent … en print deze regel als er een vervanging is gemaakt.

Het net Het effect hiervan is dat alleen die regels worden afgedrukt die eindigen op .png, met de verwijderd. Dat wil zeggen, dit komt ook tegemoet aan de lichte generalisatie van de vraag van het OP, waarbij de directory “niet alleen .png bestanden bevat.

De sed -n -techniek is vaak handig in gevallen waarin u anders grep + sed zou gebruiken.

Opmerkingen

  • Ik hou van hoe de zorg u gebruikte om uw antwoord te schrijven. Deze oplossing zal problemen opleveren met bestandsnamen, inclusief nieuwe regels , het zal niet het eerste deel van de naam afdrukken. Zeker als het een vervelender is met de sleutel (.png) voor de newline char: in dat geval print je dat deel zonder png, en wis je niet alleen het laatste deel. Het wordt vaak aangeraden om te voorkomen dat de uitvoer van ls omdat de problemen kunnen worden verborgen waar u niet aan denkt …
  • @Hastur You ‘ opnieuw correct , in principe, en de beroemde pagina over don ‘ t parse ls somt verdere problemen (en oplossingen) op bij het overhandigen van pathologische bestandsnamen. Maar de beste manier om daarmee om te gaan is om pathologische bestandsnamen te vermijden (doh!); en als je kunt ‘ t, of als je moet robuust zijn tegen hen, gebruik dan find of – mogelijk beter – gebruik een krachtigere taal dan sh om ze te beheren (het feit dat sh kan alles betekent niet ‘ t betekent dat het ‘ in elk geval de beste keuze is). De shell is eerst ontworpen voor bruikbaarheid.
  • Ik ben het in principe eens over de bruikbaarheid, maar deze variant mislukt als je een bestandsnaam hebt met elke nieuwe regel erin. Dit kan gemakkelijk onopgemerkt gebeuren, bijvoorbeeld wanneer u een regel vanuit een pdf in een GUI kopieert en plakt, dus u denkt alleen pathologische bestandsnamen te vermijden.
  • Bovendien IMHO Het ‘ is gemakkelijk te beginnen met het ontleden van ls, maar er komen toekomstige problemen mee. Vaak maken we scripts die we later zullen gebruiken, wanneer we hun limiet al zijn vergeten … (het is ‘ is menselijk, het is ‘ s gebruikelijk). Ik stelde een find voorbeeld voor (met -exec en zonder pipe) zelfs als ik een beter (omdat pure shell) acht, antwoord de cuonglm ‘ s een , solid en posix compliant.
  • Dit is ongeveer wat ik ‘ zou doen als ik, om de een of andere reden, strip de .png achtervoegsel uit een lijst met bestandsnamen.Ik zou het ‘ niet in een script plaatsen; in plaats daarvan typ ik ‘ gewoon het commando achter de shell-prompt. Dit zou een herinnering zijn dat ik ‘ m ervan uitgaande ” gezond ” bestandsnamen. Er zijn tal van dingen die ik ‘ zal doen in een eenmalige handmatige opdracht, als ik vrij ben om aannames te doen over wat ‘ in de huidige directory, wat ik waarschijnlijk niet ‘ zou doen in een script dat in een andere context zou kunnen worden hergebruikt.

Antwoord

Ik “ga voor basename (uitgaande van de GNU-implementatie):

basename --suffix=.png -- *.png 

Reacties

  • Merk op dat als je het in een pipe wilt gebruiken, je het misschien handig vindt om GNU basisnaam ‘ s -z (of --zero) optie om NUL-gescheiden te produceren (in plaats van nieuwe regel gescheiden ) output.

Answer

Je kunt alleen BASH-commandos gebruiken om dat te doen (zonder externe tools).

for file in *; do echo "${file%.*}"; done 

Dit is handig als je zonder / usr / bin bent en werkt goed voor bestandsnamen l ike this.is.image.png en voor alle extensies.

Antwoord

was het niet “niet genoeg?

ls -1 | sed "s/\.png//g" 

of in het algemeen, dit

ls -1 | sed "s/\.[a-z]*//g" 

zal alle extensies verwijderen

Reacties

  • Dat was het maar de andere oplossingen werken ook.
  • Alle Unix / Unix Like-systemen hebben (of zouden moeten hebben) sed geïnstalleerd omdat het een verplicht hulpprogramma is standaard.
  • Inderdaad, maar ls doet het hoe dan ook zonder die optie wanneer de uitvoer geen terminal is, wat hier het geval is.
  • Waarschuwing ls -1 | sed 's/\.[a-z]*//g' zal mislukken als er een bestandsnaam is als Image.png.jpg.png de hele tijd de sleutel afsnijdt (.png). Onder Unix zijn vreemde bestandsnamen toegestaan als The new art of working on .png?files and other formats.png waarbij de ? is een newline-teken. Helaas zullen alle oplossingen die simpelweg de ls -uitvoer poetsen / parseren in een probleem optreden ms beheren van dergelijke gevallen …
  • Waarom de g kwalificatie? U wilt \.png alleen aan het einde van de regel verwijderen, niet elke keer dat het verschijnt.

Antwoord

Het is niet veilig om ls te parseren of find [ 1 , 2 ]

Het is niet veilig om de uitvoer van ls of find ontleden (en om te buigen), voornamelijk omdat het mogelijk is om de bestandsnamen niet gebruikelijke tekens als de nieuwe regel , de tab … Hier zal een pure shell-cyclus werken [ cuonglm ] .
Zelfs het find commando niet doorgesluisd met de optie -exec zal werken:

find ./*.png -exec basename {} .png \; 

Updates / opmerkingen : je kunt find . gebruiken om zelfs naar verborgen bestanden te zoeken, of find ./*.png om alleen de niet-verborgen te krijgen. Met find *.png -exec ... kun je een probleem hebben in het geval dat het een bestand met de naam .png bevat, omdat find het als een optie krijgt. U kunt -maxdepth 0 toevoegen om te voorkomen dat u afdaalt in mappen met de naam Dir_01.png, of find ./*.png -prune -exec ... wanneer maxdepth is niet toegestaan (bedankt Stéphane). Als u deze mappen niet wilt weergeven, moet u de optie -type f toevoegen (waardoor ook andere typen niet-reguliere bestanden worden uitgesloten). Kijk eens naar de man voor een completer overzicht van alle beschikbare opties, en vergeet niet te controleren of ze POSIX-compatibel zijn, voor een betere draagbaarheid.

Nog een paar woorden

Het kan bijvoorbeeld gebeuren dat het kopiëren van de titel uit een document en het plakken in de bestandsnaam, een of meer nieuwe regels in de bestandsnaam zelf eindigen.We kunnen zelfs de pech hebben dat een titel zelfs de sleutel kan bevatten die we moeten gebruiken net voor een nieuwe regel:

The new art of working on .png files and other formats. 

Als je wilt testen, kun je maak bestandsnamen op deze manier met de commandos

touch "A file with two lines"$"\n""and This is the second.png" touch "The new art of working on .png"$"\n""files and other formats.png" 

De simpele /bin/ls *png zal in plaats van de niet-afdrukbare tekens

A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png 

In alle gevallen waarin u pipe de uitvoer van ls of find het volgende commando heeft geen hint om te begrijpen als de huidige regel afkomstig is van een nieuwe bestandsnaam of als deze volgt op een nieuwe regel -teken in de voorgaande bestandsnaam . Een vervelende naam inderdaad, maar nog steeds een legale naam.

Een shell-cyclus met een shell Parameter-Expansion, ${parameter%word}, in beide de variant met printf of echo zal [ cuonglm ], [ Anthon1 ] .

for f in *.png; do printf "%s\n" "${f%.png}" ; done 

Van de man-pagina van de Shell Parameter Expansion [ 3 ]

$ {parameter% word}
$ {parameter %% word}

… het resultaat van de uitbreiding is de waarde van de parameter met het kortste overeenkomende patroon (het % geval) of het langste overeenkomende patroon (de %% case) verwijderd.

Reacties

  • Ook de resultaten van uw find commando zijn een beetje variabel (bijvoorbeeld als er een map is met de naam files.png)
  • Beste @BroSlow, toen ik het antwoord hierboven schreef Ik probeerde 13 (alle) van de andere varianten die op dat moment aanwezig waren, via de opdrachtregel, in een script, gestart als argument van een shell-aanroep. Doe hetzelfde en vertel me of ze zich gedragen zoals u verwacht. Ik heb mijn tests gedaan met bash 4.3.11, streepje 0.5.7-4, zsh (indien nodig) 5.0.2. Voel je vrij om dit bericht te lezen dat iets meer toevoegt. Ik ben het eens met de opmerking van piping de uitvoer van find, hiervoor heb ik uitdrukkelijk -exec voorgesteld , en ik schreef in de titel. :-).
  • Lees de wiki opnieuw. Ik denk nog steeds dat je in je voorbeeld moet pijpen, aangezien ‘ is wat ‘ s hier wordt besproken. En voor de meeste moderne versies van ls is er geen enkel probleem wanneer de uitvoer wordt doorgesluisd of omgeleid, maar zoals vermeld in de wiki, werkt het misschien niet voor iedereen. De meeste zullen alleen de ? invoegen in plaats van speciale tekens wanneer de uitvoer naar de terminal wordt gestuurd. d.w.z. doe echo *.png | od -c en ls *.png | od -c. Het probleem met de nieuwe regel is geen probleem met ls, het is ‘ een probleem met elke opdracht die niet ‘ t null eindigt aan beide zijden van de pipe.
  • printf "${f%.png}\n" is verkeerd. Het eerste argument is het formaat, je mag ‘ t geen variabele data gebruiken. Kan zelfs worden gezien als een DoS-kwetsbaarheid (probeer bijvoorbeeld met een %1000000000s.png -bestand).
  • Jij ‘ d find ./*.png -prune -exec... of u ‘ problemen hebt met bestandsnamen die beginnen met - (en bestanden van type directory, merk op dat -maxdepth niet draagbaar is)

Answer

Gebruik rev:

ls -1 | rev | cut -f 2- -d "." | rev 

rev keert alle snaren (lijnen); je snijdt alles na de eerste “.” en rev keert het overblijfsel terug.

Als je grep “alma” wilt:

ls -1 | rev | cut -f 2- -d "." | rev | grep "alma" 

Reacties

  • De -1 is niet nodig, aangezien dit hier de standaard is.
  • Dit mislukt slecht op een bestand met de naam My.2016.Summer.Vacation.png
  • @DavidConrad mijn fout: / ik heb gecorrigeerd naar cut -f 2-
  • Nu werkt het met dat bestand, maar nog niet met een bestand met .png en een nieuwe regel net na … Het wordt aangeraden om omdat het ervan houdt om de verrassingen goed te verbergen … 🙂

Antwoord

Als ik wist dat de directory alleen bestanden had met .png als extensie, had ik het volgende uitgevoerd: ls | awk -F. "{print $1}"

Dit zal het eerste “veld” voor alles met een bestandsnaam.extensie.

Voorbeeld:

[rsingh@rule51 TESTDIR]$ ls 10.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png [rsingh@rule51 TESTDIR]$ ls | awk -F. "{print $1}" 10 1 2 3 4 5 6 7 8 9 

Reacties

  • Helaas zal het op alle de bestandsnamen met meer dan één ., als Image.1.png en zelfs die met niet leuk namen , met daarin speciale tekens. als de nieuwe regel of degene die u als (invoer) recordscheidingsteken zult gebruiken in awk, RS. Het wordt aangeraden om te vermijden om de ls -uitvoer te ontleden, omdat het graag problemen verbergt die zich voordoen wanneer je het niet verwacht. U kunt meer lezen in die verwijzing 1 of 2 . Trouwens, het idee om awk te gebruiken … Ik heb wat voorbeelden in één antwoord gestopt.
  • Dat is waar, maar gezien het voorbeeld van Colin zou het prima werken. Om het te laten werken voor het geval dat u voorstelde, heb ik ‘ het waarschijnlijk gewijzigd in: [rsingh @ rule51 TESTDIR] $ ls | sed -e ‘ s / .png $ // ‘ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats .a.png.filename Ik probeer niet moeilijk te zijn, maar gezien Colin ‘ s behoefte, ‘ weet ik niet zeker wat het probleem zou zijn ls ontleden.
  • sorry … ik realiseerde me net dat ik ‘ de map met de bestanden niet heb getoond voordat sed de uitvoer van ‘ ls ‘ [rsingh @ rule51 TESTDIR] $ ls 10.png 2.png 4.png 6.png 8.png harry.the.bunny. png 1.png 3.png 5.png 7.png 9.png whats.a.png.filename.png [rsingh @ rule51 TESTDIR] $ ls | sed -e ‘ s / .png $ // ‘ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny whats .a.png.filename
  • note1 je moet de . in \. binnen de sed -e 's/\.png$//', maar zo wordt het een zojuist geschreven antwoord. 🙁 note2 je kunt proberen awk te gebruiken met iets als ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … maar je zult altijd het probleem dat awk niet kan weten of de regel aankomt, volgt een nieuwe regel in de bestandsnaam. Ik probeerde het beter te zeggen in mijn antwoord.
  • Bedankt Hastur, dat heb ik gemist :). Ook heb ik in dit geval het gebruik van awk geschrapt ten gunste van sed.

Answer

volgens jouw comment “Ik heb een tekstbestand waarin alle namen worden vermeld zonder de extensie. Ik wil een PHP-script maken dat het tekstbestand vergelijkt met de map om te zien welk bestand ontbreekt”:

for file in $(cat yourlist) ; do [ -f "${file}.png" ] || { echo "$file : listed in yourlist, but missing in the directory" } done #assumes that filenames have no space... # otherwise use instead: # while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist 

en omgekeerd:

for file in *.png ; do grep "^${file%.png}$" yourlist >/dev/null || { echo "$file: present in the directory but not listed in yourlist" } done #I assume there are no spaces/tabs/? before/after names in "yourlist". Change the script accordingly if there are some (or sanitize the list) 

Antwoord

ls -l | sed "s/\.png$//"

Is de meest nauwkeurige methode zoals benadrukt door @roaima. Zonder de ontsnapte \.png bestanden met de naam a_png.png zouden worden weergegeven als: a_.

Reacties

  • gebruik van ls -l, zoals je doet, geeft de bestandsdetails, dat is niet wat het OP vroeg ongeveer.

Antwoord

Een eenvoudige shell-regel (ksh, bash of zsh; geen streepje):

set -- *.png; printf "%s\n" "${@%.png}" 

Een eenvoudige functie (van geen extensie):

ne(){ set -- *.png; printf "%s\n" "${@%.png}"; } 

Of een functie die verwijdert elke gegeven extensie (standaard png):

ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; } 

Gebruiken als:

ne jpg 

Als de uitvoer een asterisk is *, bestaat er geen bestand met die extensie.

Antwoord

Je kunt de volgende feed proberen, terwijl de uitvoer van ls je superator de “.” en aangezien al uw bestanden de naam.png hebben, drukt u de eerste kolom af:
ls | awk -F"." "{print $1}"

Antwoord

Als je toegang hebt tot sed, is dit beter aangezien het de laatste bestandsextensie zal verwijderen, ongeacht wat het is (png, jpg, tiff, enz …)

ls | sed -e "s/\..*$//" 

Reacties

  • Onderbrekingen voor bestandsnamen zoals this.is.a.dotty.txt. Probeer in plaats daarvan s/\.[^.]*$//.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *