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
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
printfniet 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
-1is niet nodig, aangezien dit hier de standaard is. - @jlliagre Ik ben het met cas eens dat de
-1moet 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.pngwissen 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
finddoorgesluisd naarsedoplossing 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 vanfindoflsdoor te sluizen en te ontleden, het reserveert vaak goed verborgen verrassingen … (enkele woorden en meer verwijzingen in het antwoord). - Vervang waarschijnlijk
finddoor iets alsechoin het laatste voorbeeld. Het is niet duidelijk welk doelfinddaar dient en de resultaten zijn afhankelijk van de directorystructuur (bijv. Of u een directoryfiles.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
-1niet nodig optie naarls, aangezienlservan uitgaat dat als de standaarduitvoer niet “ta terminal is (het is in dit geval een pijp). - de
-noptie naarsedbetekent de regel niet standaard afdrukken - de
/poptie 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 vanlsomdat 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
findof – mogelijk beter – gebruik een krachtigere taal danshom ze te beheren (het feit datshkan 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 eenfindvoorbeeld voor (met-execen 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
.pngachtervoegsel 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)
sedgeïnstalleerd omdat het een verplicht hulpprogramma is standaard. - Inderdaad, maar
lsdoet 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 alsImage.png.jpg.pngde hele tijd de sleutel afsnijdt (.png). Onder Unix zijn vreemde bestandsnamen toegestaan alsThe new art of working on .png?files and other formats.pngwaarbij de?is een newline-teken. Helaas zullen alle oplossingen die simpelweg dels-uitvoer poetsen / parseren in een probleem optreden ms beheren van dergelijke gevallen … - Waarom de
gkwalificatie? U wilt\.pngalleen 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
findcommando zijn een beetje variabel (bijvoorbeeld als er een map is met de naamfiles.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 vanfind, hiervoor heb ik uitdrukkelijk-execvoorgesteld , 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
lsis 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. doeecho *.png | od -cenls *.png | od -c. Het probleem met de nieuwe regel is geen probleem metls, 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-maxdepthniet 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
-1is 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
.pngen 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
., alsImage.1.pngen zelfs die met niet leuk namen , met daarin speciale tekens. als de nieuwe regel of degene die u als (invoer) recordscheidingsteken zult gebruiken inawk,RS. Het wordt aangeraden om te vermijden om dels-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 desed -e 's/\.png$//', maar zo wordt het een zojuist geschreven antwoord. 🙁 note2 je kunt proberenawkte gebruiken met iets alsls | 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 daarvans/\.[^.]*$//.
.bevatten. Hoewel de conventie zegt dat je je bestanden een naam moet geven met.pngaan het einde, is er geen reden waarom ik ‘ geen png-bestand kan hebben met de naamfoo.zipofmy.picture.20160518of gewoonmypic.lsen om de output vanlsenfinddoor te sluizen, voornamelijk vanwege de mogelijkheid omnewline,` tab char in de bestandsnaam. Als de bestandsnaamThe new art of working on .png\NEWLINE files and other formatsis, zullen veel van de voorgestelde oplossingen problemen veroorzaken.