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
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 naarsed
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 vanfind
ofls
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 alsecho
in het laatste voorbeeld. Het is niet duidelijk welk doelfind
daar 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
-1
niet nodig optie naarls
, aangezienls
ervan uitgaat dat als de standaarduitvoer niet “ta terminal is (het is in dit geval een pijp). - de
-n
optie naarsed
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 vanls
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 dansh
om ze te beheren (het feit datsh
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 eenfind
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 alsImage.png.jpg.png
de hele tijd de sleutel afsnijdt (.png
). Onder Unix zijn vreemde bestandsnamen toegestaan alsThe new art of working on .png?files and other formats.png
waarbij 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
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 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-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. doeecho *.png | od -c
enls *.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-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
.
, alsImage.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 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 proberenawk
te 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.png
aan het einde, is er geen reden waarom ik ‘ geen png-bestand kan hebben met de naamfoo.zip
ofmy.picture.20160518
of gewoonmypic
.ls
en om de output vanls
enfind
door 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 formats
is, zullen veel van de voorgestelde oplossingen problemen veroorzaken.