' ls -1 ': hur man listar filnamn utan förlängning

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

  • Du vill vara försiktig med en sådan begäran. Linux har inte filnamnstillägg. Linux har filnamn som kanske innehåller en . 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 namnet foo.zip eller my.picture.20160518 eller bara mypic.
  • @hymie I vet, men mina element i den mappen heter alla med .png i slutet.
  • Vad ’ är en ” förlängning ”? Att ’ inte ingår i Unix-filnamn; det ’ s överföring från VMS / NT / Windows vad som helst. Och ni ungdomar går av min gräsmatta också. 🙂
  • Låt ’ inte överdriva detta. OS behandlar tillägg som helt enkelt en del av filnamnet, men många unix-program är uppmärksamma på dem, från kompilatorn till GUI. Konceptet är absolut inte främmande för unix.
  • Det föreslås vanligtvis att undvika att analysera utdata från ls och för att pipa utdata från ls och find, främst för att möjligheten att uppstå i newline,` tab char i filnamnet. Om filnamnet är The new art of working on .png\NEWLINE files and other formats kommer många av de föreslagna lösningarna att skapa problem.

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 till sed 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ån find eller ls, 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 som echo i det sista exemplet. Inte klart vilket syfte find tjänar där och resultaten beror på katalogstrukturen (dvs. om du har en katalog files.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 till ls, eftersom ls förutsätter att om standardutgången inte är en terminal (det är ett rör, i detta fall).
  • alternativet -n till sed 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ån ls 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 än sh för att hantera dem (det faktum att sh 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 ett find 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 som Image.png.jpg.png skär hela tiden tangenten (.png). Under Unix tillåts konstiga filnamn som The 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 / analyserar ls 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 heter files.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ån find, 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ör echo *.png | od -c och ls *.png | od -c. Newline-frågan är inte ett problem med ls, 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 analysera ls 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 ., som Image.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 i awk, RS. Det rekommenderas att man undviker att analysera ls -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 \. inuti sed -e 's/\.png$//', men så blir det ett svar som bara är skrivet. 🙁 note2 du kan försöka använda awk med något som ls | 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 med s/\.[^.]*$//.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *