ls -1
listar mina element så här:
foo.png bar.png foobar.png ...
Jag vill ha det listat utan .png
så här:
foo bar foobar ...
(dir innehåller endast .png
filer)
Kan någon berätta för mig hur man använder grep
i det här fallet?
Syfte: Jag har en textfil där alla namn är listade utan förlängning. Jag vill skapa ett skript som jämför textfilen med mappen för att se vilken fil som saknas.
Kommentarer
Svar
Du behöver bara skalet för det här jobbet.
POSIXly:
for f in *.png; do printf "%s\n" "${f%.png}" done
Med zsh
:
print -rl -- *.png(:r)
Kommentarer
- Där ’ behöver inte
printf
;echo ${f%.png}
räcker. - @Conrad: med echo kommer ’ inte att fungera korrekt i vissa fall, om filnamnet börja med bindestreck eller innehålla räddade sekvenser.
- @DavidConrad: Se även unix.stackexchange.com/a/65819/38906
- @ DavidConrad Jag tror dessutom att printf är inbyggt, precis som eko, någon korrigerar mig om jag ’ har fel
Svar
ls -1 | sed -e "s/\.png$//"
Kommandot sed
tar bort (det vill säga den ersätter med den tomma strängen) vilken sträng som helst .png
som finns i slutet ett filnamn.
.
undviks som \.
så att det tolkas av sed
som ett bokstavligt .
-tecken snarare än regexp .
(vilket betyder matcha alla ch aracter). $
är ankaret i slutet, så det matchar inte .png
mitt i ett filnamn.
Kommentarer
- Jag tror att OP vill att någon förlängning ska tas bort, men förmodligen bara ” sista ”. Så kanske ändra ditt annars bra svar med:
sed 's/\.[^.]*$//'
- ja, den regexp skulle fungerar i så fall … men om OP vill ha det borde de säga det istället för att specifikt säga att de ” vill att det ska listas utan .png ”
-
-1
är inte nödvändigt, eftersom det är standard här. - @jlliagre Jag håller med cas att
-1
bör anges. Det ’ är bara standard när röret är påslaget, vilket är en dold överraskning för vissa. Så att göra det uttryckligt hjälper Jag gör det också i mina manus så jag vet vilken typ av o utdata I ’ jag förväntar mig. - Varning Vid filnamn med nyckeln (
.png
) före en ny linje-rad raderar du även den.png
och inte bara den sista. Det är bättre att undvika att pipa och analysera resultatet av ls, det förbehåller sig ofta väl dolda överraskningar … (några ord och referenser mer i svaret).
Svar
Om du bara vill använda bash:
for i in *; do echo "${i%.png}"; done
Du bör nå grep
när du försöker hitta matchningar, inte för att ta bort / ersätta det som sed
är mer lämpligt:
find . -maxdepth 1 -name "*.png" | sed "s/\.png$//"
När du väl har bestämt dig för att du behöver skapa några underkataloger för att få ordning på dina PNG-filer kan du enkelt ändra det till:
find . -name "*.png" | sed "s/\.png$//"
Kommentarer
- ls -1 | sed ’ s / .png // ’ fungerar bra. Tack!
-
find
piped tillsed
kan ge några problem om du hittar en fil med nyckeln (.png
) som en del av namnet och strax före en nylinjetecken. Det är bättre att undvika att pipa och analysera utdata frånfind
ellerls
, det förbehåller sig ofta väl dolda överraskningar … (några ord och referenser mer i svaret). - Förmodligen ersätt
find
med något somecho
i det sista exemplet. Inte klart vilket syftefind
tjänar där och resultaten beror på katalogstrukturen (dvs. om du har en katalogfiles.png
) - @BroSlow Uppdaterad till något mer förnuftigt.
Svar
Ett annat mycket liknande svar (jag förvånade detta särskild variant har inte dykt upp ännu är:
ls | sed -n "s/\.png$//p"
- Du behöver inte
-1
alternativ tillls
, eftersomls
förutsätter att om standardutgången inte är en terminal (det är ett rör, i detta fall). - alternativet
-n
tillsed
betyder att ”inte skriva ut raden som standard” - alternativet
/p
i slutet av utbytet betyder ”… och skriv ut den här raden om en utbyte gjordes”.
Nätet effekten av det är att bara skriva ut de rader som slutar på .png
, med borttagen. Det vill säga detta riktar sig också till en liten generalisering av OP: s fråga, där katalogen inte bara innehåller .png
-filer.
sed -n
-teknik är ofta användbar i fall där du annars kan använda grep + sed.
Kommentarer
- Jag gillar hur vården du brukade skriva ditt svar. Den här lösningen kommer att ge problem med filnamn inklusive nya rader , den kommer inte att skriva ut den första delen av namnet. Ännu mer om den är snyggare med nyckeln (
.png
) före den nya raden: i så fall skriver du ut den delen utan png och raderar inte bara den sista delen. Det rekommenderas ofta att undvika att analysera (och pipera) utdata frånls
eftersom problemen kan döljas precis där du inte funderar på … - @Hastur Du ’ är korrekt i princip och den berömda sidan om don ’ t parse ls listar ytterligare problem (och lösningar) när du lämnar patologiska filnamn. Men det bästa sättet att hantera det är att undvika att ha patologiska filnamn (doh!); och om du kan ’ t, eller om du måste vara robust mot dem, använd antingen
find
eller – möjligen bättre – använd ett kraftfullare språk änsh
för att hantera dem (det faktum attsh
kan göra allt betyder inte ’ t att det ’ är det bästa valet i varje fall). Skalet är utformat för användbarhet först. - Jag håller i princip med om användbarheten, men den här varianten misslyckas när du har ett filnamn med varje ny rad inuti. Detta kan lätt inträffa obemärkt, till exempel när du kopierar och klistrar in en rad från en pdf i ett GUI, så du tänker bara att undvikas patologiska filnamn .
- Dessutom IMHO Det är ’ det är lätt att börja analysera
ls
, men det handlar om framtida problem. Ofta gör vi skript som vi kommer att använda senare, när vi redan kommer att glömma deras gräns … (det ’ s mänskligt, det ’ är vanligt). Jag föreslog ettfind
exempel (med-exec
och utan rör) även om jag anser att det är bättre (för rent skal) svara på cuonglm ’ en , solid och posix-kompatibel. - Det här är ganska mycket vad jag ’ skulle göra om jag av någon anledning ville ta bort
.png
suffix från en lista med filnamn.Jag skulle inte ’ inte lägga in det i ett manus; istället skrev jag ’ bara kommandot vid skalprompten. Att göra det skulle vara en påminnelse om att jag ’ m antar ” sane ” filnamn. Det finns många saker jag ’ gör i ett engångsmanualkommando när jag gärna gör antaganden om vad ’ i den aktuella katalogen, att jag förmodligen inte ’ skulle göra i ett skript som kan återanvändas i något annat sammanhang.
Svar
Jag skulle gå för basename
(förutsatt att GNU-implementeringen):
basename --suffix=.png -- *.png
Kommentarer
- Observera att om du vill använda den i ett rör kan det vara bra att använda GNU-basnamn ’ s
-z
(eller--zero
) för att producera NUL-separerad (istället för newline-separerad ) output.
Svar
Du kan bara använda BASH-kommandon för att göra det (utan externa verktyg).
for file in *; do echo "${file%.*}"; done
Detta är användbart när du är utan / usr / bin och fungerar bra för filnamn l ike this.is.image.png och för alla tillägg.
Svar
var det inte tillräckligt?
ls -1 | sed "s/\.png//g"
eller i allmänhet tar detta
ls -1 | sed "s/\.[a-z]*//g"
bort alla tillägg
Kommentarer
- Det var men de andra lösningarna fungerar också.
- Alla Unix / Unix-liknande system har (eller borde ha)
sed
installerat eftersom det är ett obligatoriskt verktyg enligt standarden. - Faktiskt, men
ls
gör det ändå utan det alternativet när dess utdata inte är en terminal, vilket är fallet här. - Varning
ls -1 | sed 's/\.[a-z]*//g'
misslyckas om det finns ett filnamn somImage.png.jpg.png
skär hela tiden tangenten (.png
). Under Unix tillåts konstiga filnamn somThe new art of working on .png?files and other formats.png
där?
är en ny linje karaktär. Tyvärr kommer alla lösningar som helt enkelt rör / analyserarls
utgången i proble ms hanterar sådana fall … - Varför
g
kvalet? Du vill ta bort\.png
bara i slutet av raden, inte varje gång den visas.
Svar
Det är inte säkert att analysera ls
eller att pipa find
[ 1 , 2 ]
Det är inte säkert att analysera (och för att pipa) utdata från ls
eller find
, främst för att det är möjligt att hitta i filnamnen icke vanliga tecken som newline , fliken … Här fungerar en ren skalcykel [ cuonglm ] .
Även find
-kommandot inte piped med alternativet -exec
fungerar:
find ./*.png -exec basename {} .png \;
Uppdateringar / anteckningar : Du kan använda find .
för att söka även efter de dolda filerna, eller find ./*.png
för att bara få de inte dolda. Med find *.png -exec ...
kan du få problem i fallet att det fanns en fil med namnet .png
eftersom find kommer att få det som ett alternativ. Du kan lägga till -maxdepth 0
för att undvika att sjunka ned i kataloger som heter Dir_01.png
eller find ./*.png -prune -exec ...
när maxdjup är inte tillåtet (tack Stéphane). Om du vill undvika att lista dessa kataloger bör du lägga till alternativet -type f
(vilket också skulle utesluta andra typer av icke-vanliga filer). Ta en titt på man
för ett mer fullständigt panorama över alla tillgängliga alternativ, och kom ihåg att kontrollera när de är POSIX-kompatibla, för en bättre bärbarhet.
Några ord mer
Det kan till exempel hända att kopiering av titeln från ett dokument och klistra in i filnamnet, en eller flera nya rader kommer att avslutas i själva filnamnet.Vi kan till och med vara så olyckliga att en titel kan innehålla till och med den nyckel vi måste använda strax före en ny rad:
The new art of working on .png files and other formats.
Om du vill testa kan du skapa filnamn som detta med kommandona
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"
Den enkla /bin/ls *png
matar ut ?
istället för de icke utskrivbara tecknen
A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png
I alla fall där du kommer rör utgången av ls
eller find
följande kommando har ingen ledtråd att förstå om den aktuella raden kommer från ett nytt filnamn eller om det följer ett newline -tecken i det föregående filnamnet . Ett otäckt namn faktiskt, men ändå ett lagligt namn.
En skalcykel med ett skal Parameter-expansion, ${parameter%word}
, i båda varianten med printf
eller echo
fungerar [ cuonglm ], [ Anthon1 ] .
for f in *.png; do printf "%s\n" "${f%.png}" ; done
Från mansidan av Shell Parameter Expansion [ 3 ]
$ {parameter% word}
$ {parameter %% word}… resultatet av expansionen är värdet på parametern med det kortaste matchningsmönstret (fallet %) eller längsta matchande mönstret (fallet %%) har tagits bort.
Kommentarer
- Även resultaten av din
find
kommando är lite variabla (till exempel om det finns en katalog som heterfiles.png
) - Kära @BroSlow, när jag skrev svaret ovan I försökte 13 (alla) andra varianter som var närvarande i det ögonblicket, med kommandoraden, i ett manus, som lanserades som argument för en skalanrop. Snälla gör samma sak och berätta för mig om de beter sig som du förväntar dig. Jag gjorde mina tester med
bash 4.3.11
, streck 0.5.7-4, zsh (vid behov) 5.0.2. Du är välkommen att läsa det här inlägget som lägger till något mer. Jag håller med om noteringen av piping utdata frånfind
, för detta föreslog jag uttryckligen-exec
, och jag skrev i titeln.:-)
. - Läs igen wiki igen. Jag tror fortfarande att du måste peka i ditt exempel, eftersom det ’ är vad ’ diskuteras här. Och för de flesta moderna versioner av
ls
finns det inget som helst problem när utdata pipas eller omdirigeras, men som nämnts i wiki kanske det inte fungerar för alla. De flesta infogar bara?
istället för specialtecken när utdata skickas till terminal. dvs. görecho *.png | od -c
ochls *.png | od -c
. Newline-frågan är inte ett problem medls
, det ’ är ett problem med något kommando som inte ’ t null avslutas över båda sidor av röret. -
printf "${f%.png}\n"
är fel. Det första argumentet är formatet, du bör inte ’ inte använda variabel data där. Kan till och med ses som en DoS-sårbarhet (försök med en%1000000000s.png
-fil till exempel). - Du ’ d behöver
find ./*.png -prune -exec...
eller så har du ’ problem med filnamn som börjar med-
(och filer med typkatalog, notera att-maxdepth
inte är bärbar)
Svar
Använd rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
reverserar alla strängar (linjer); du skär allt efter den första ”.” och rev återför återstoden.
Om du vill grep
”alma”:
ls -1 | rev | cut -f 2- -d "." | rev | grep "alma"
Kommentarer
-
-1
är inte nödvändigt, eftersom det är standard här. - Detta misslyckas dåligt i en fil med namnet
My.2016.Summer.Vacation.png
- @DavidConrad min dåliga: / Jag har korrigerat till
cut -f 2-
- Nu fungerar den med den filen men ännu inte med en fil med
.png
och en ny rad strax efter … Det föreslås att man undgår att analyserals
eftersom det älskar att dölja väl överraskningarna … 🙂
Svar
Om jag visste att katalogen bara hade filer med .png som ett tillägg, skulle jag bara ha kört: ls | awk -F. "{print $1}"
Detta returnerar det första ”fältet” för allt där det finns ett filnamn. förlängning.
Exempel:
[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
Kommentarer
- Tyvärr misslyckas det på alla filnamnen med mer än en
.
, somImage.1.png
och även på de med inte trevliga namn , med specialtecken inuti. som den nya raden eller den som du kommer att använda som (ingång) inspelningsavgränsare iawk
,RS
. Det rekommenderas att man undviker att analyserals
-utdata eftersom det älskar att dölja problem som uppstår när man inte förväntar sig. Du kan läsa mer i referensen 1 eller 2 . BTW trevligt idén att använda awk … Jag lade några exempel i ett svar. - Det är sant, men med tanke på det prov som tillhandahållits av Colin skulle det fungera bra. För att få det att fungera för det fall du föreslog ändrade jag antagligen ’ till: [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 Försöker inte vara svårt, men med tanke på Colin ’ s behov, jag ’ är inte säker på vad problemet skulle göra analysera ls.
- ledsen … Jag insåg precis att jag inte ’ inte visade katalogen med filerna innan jag ändrade utdata från ’ 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 du måste undkomma
.
i\.
inutised -e 's/\.png$//'
, men så blir det ett svar som bara är skrivet. 🙁 note2 du kan försöka användaawk
med något somls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
… men du kommer att ha alltid problemet som awk inte kan veta om raden anländer följer eller inte en ny rad inuti filnamnet. Jag försökte säga bättre i mitt svar. - Tack Hastur, jag saknade det :). Jag drog också bort användningen av awk till förmån för sed i detta fall.
Svar
enligt din kommentar ”Jag har en textfil där alla namnen är listade utan tillägget. Jag vill skapa ett PHP-skript som jämför textfilen med mappen för att se vilken fil som saknas”:
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
och omvänd:
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)
Svar
ls -l | sed "s/\.png$//"
Är den mest exakta metoden som markeras av @roaima. Utan de undantagna \.png
filer som heter a_png.png
listas som: a_
.
Kommentarer
- med
ls -l
, som du gör, ger filinformation, det är inte vad OP frågade om.
Svar
En enkel skallinje (ksh, bash eller zsh; inte bindestreck):
set -- *.png; printf "%s\n" "${@%.png}"
En enkel funktion (från No Extension):
ne(){ set -- *.png; printf "%s\n" "${@%.png}"; }
Eller en funktion som tar bort valfritt tillägg (png som standard):
ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; }
Använd som:
ne jpg
Om utdata är en asterisk *
, finns ingen fil med det tillägget.
Svar
Du kan prova följande flöde awk resultatet av ls din superator är ”.” och eftersom alla dina filer kommer att ha name.png skriver du ut den första kolumnen:
ls | awk -F"." "{print $1}"
Svar
Om du har tillgång till sed är det bättre eftersom det tar bort det sista filtillägget, oavsett vad det är (png, jpg, tiff, etc …)
ls | sed -e "s/\..*$//"
Kommentarer
- Bryter för filnamn som
this.is.a.dotty.txt
. Försök istället meds/\.[^.]*$//
.
.
i dem. Även om konventionen säger att namnge dina filer med.png
i slutet, finns det ingen anledning till att jag ’ inte kan ha en png-fil med namnetfoo.zip
ellermy.picture.20160518
eller baramypic
.ls
och för att pipa utdata frånls
ochfind
, främst för att möjligheten att uppstå inewline
,` tab char i filnamnet. Om filnamnet ärThe new art of working on .png\NEWLINE files and other formats
kommer många av de föreslagna lösningarna att skapa problem.