' ls -1 ': hvordan du viser filnavn uten filtype

ls -1 lister elementene mine slik:

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

Jeg vil at den skal være oppført uten .png slik:

foo bar foobar ... 

(dir inneholder bare .png filer)

Kan noen fortelle meg hvordan jeg bruker grep i dette tilfellet?

Formål: Jeg har en tekstfil der alle navnene er oppført uten Utvidelse. Jeg vil lage et skript som sammenligner tekstfilen med mappen for å se hvilken fil som mangler.

Kommentarer

  • Du vil være forsiktig med en forespørsel som denne. Linux har ikke filnavnutvidelser. Linux har filnavn som kanskje inneholder en . i dem. Selv om konvensjonen sier å navngi filene dine med .png på slutten, er det ingen grunn til at jeg ‘ ikke kan ha en png-fil som heter foo.zip eller my.picture.20160518 eller bare mypic.
  • @hymie I vet, men elementene mine i den mappen heter alle med .png på slutten.
  • Hva ‘ er en » utvidelse «? At ‘ ikke er en del av Unix-filnavnet; det ‘ s overføring fra VMS / NT / Windows uansett. Og dere unge går også av plenen min. 🙂
  • La ‘ ikke overdrive dette. OS behandler utvidelser som bare å være en del av filnavnet, men mange unix-programmer tar hensyn til dem, fra kompilatoren til GUI. Konseptet er absolutt ikke fremmed for unix.
  • Det foreslås vanligvis å unngå å analysere utgangen av ls og for å pipe utgangen til ls og find, hovedsakelig fordi muligheten til å pådra seg i newline,` tab char i filnavnet. Hvis filnavnet er The new art of working on .png\NEWLINE files and other formats, vil mange av løsningsforslaget skape problemer.

Svar

Du trenger bare skallet for denne jobben.

POSIXly:

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

Med zsh:

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

Kommentarer

  • Der ‘ trenger ikke printf; echo ${f%.png} vil være tilstrekkelig.
  • @Conrad: bruk av ekko vant ‘ t fungerer i noen tilfeller riktig, hvis filnavnet start med bindestrek eller innehold rømte sekvenser.
  • @DavidConrad: Se også unix.stackexchange.com/a/65819/38906
  • @ DavidConrad I tillegg tror jeg printf er innebygd, akkurat som ekko, noen retter meg hvis jeg ‘ tar feil

Svar

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

sed -kommandoen fjerner (det vil si den erstatter med den tomme strengen) hvilken som helst streng .png funnet i slutten et filnavn.

. unnslippes som \. slik at det tolkes av sed som et bokstavelig . -tegn i stedet for regexp . (som betyr at alle ch aracter). $ er slutten på linjeankeret, så det samsvarer ikke med .png midt i et filnavn.

Kommentarer

  • Jeg tror OP vil ha enhver utvidelse fjernet, men sannsynligvis bare » siste «. Så kanskje endre det ellers gode svaret ditt med: sed 's/\.[^.]*$//'
  • ja, den regexp ville fungerer i så fall … men hvis OP vil ha det, bør de si det i stedet for å spesifikt si at de » vil at det skal være oppført uten .png »
  • -1 er ikke nødvendig, som standard her.
  • @jlliagre Jeg er enig med cas at -1 bør spesifiseres. Det ‘ er bare standard når rør er slått på, noe som er en skjult overraskelse for noen. Så å gjøre det eksplisitt hjelper Jeg gjør dette også i skriptene mine, slik at jeg vet hva slags o utgang jeg ‘ jeg forventer.
  • Advarsel I tilfelle et filnavn med nøkkelen (.png) før en nylinjetegn vil du slette til og med den .png og ikke bare den siste. Det er bedre å unngå å pipe og analysere utdataene fra ls, det reserverer ofte godt skjulte overraskelser … (noen ord og referanser mer i svaret).

Svar

Hvis du bare vil bruke bash:

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

Du bør nå grep når du prøver å finne treff, ikke for å fjerne / erstatte det som sed mer passende:

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

Når du bestemmer deg for at du må opprette noen underkataloger for å få orden i PNG-filene dine, kan du enkelt endre det til:

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

Kommentarer

  • ls -1 | sed ‘ s / .png // ‘ fungerer bra. Takk!
  • find piped til sed løsningen kan by på noen problemer hvis du finner en fil med nøkkelen (.png) som en del av navnet og like før et nytt linjetegn. Det er bedre å unngå å pipe og analysere utgangen av find eller ls, det reserverer ofte godt skjulte overraskelser … (noen ord og referanser mer i svaret).
  • Erstatt sannsynligvis find med noe sånt som echo i det siste eksemplet. Ikke klart hvilket formål find tjener der, og resultatene avhenger av katalogstruktur (dvs. hvis du har en katalog files.png)
  • @BroSlow Oppdatert til noe mer fornuftig.

Svar

Et annet veldig likt svar (jeg overrasket dette bestemt variant har ikke vist seg ennå) er:

ls | sed -n "s/\.png$//p" 
  • Du trenger ikke -1 alternativ til ls, siden ls forutsetter at hvis standardutgangen ikke er en terminal (det er et rør, i dette tilfellet).
  • -n alternativet til sed betyr «ikke skriv ut linjen som standard»
  • alternativet /p på slutten av erstatningen betyr «… og skriv ut denne linjen hvis det ble foretatt en erstatning».

Nettet effekten av det er å skrive ut bare linjene som ender på .png, med fjernet. Dette henvender seg også til en liten generalisering av OPs spørsmål, der katalogen ikke bare inneholder .png filer.

sed -n teknikk er ofte nyttig i tilfeller der du ellers kan bruke grep + sed.

Kommentarer

  • Jeg liker hvordan pleien du pleide å skrive svaret. Denne løsningen vil gi problemer med filnavn, inkludert nye linjer , den vil ikke skrive ut den første delen av navnet. Enda mer hvis det er en styggere med nøkkelen (.png) før den nye linjen: i så fall vil du skrive ut den delen uten png, og ikke slette bare den siste delen. Det anbefales ofte å unngå å analysere (og pipe) utgangen fra ls fordi problemene kan skjules akkurat der du ikke tenker på …
  • @Hastur Du ‘ er riktig , i prinsippet, og den berømte siden om don ‘ t parse ls viser ytterligere problemer (og løsninger) når du gir patologiske filnavn. Men den beste måten å håndtere det på er å unngå å ha patologiske filnavn (doh!); og hvis du kan ‘ t, eller hvis du være robust mot dem, så bruk enten find eller – muligens bedre – bruk et kraftigere språk enn sh for å administrere dem (det faktum at sh kan alt betyr ikke ‘ t at det ‘ er det beste valget i hvert tilfelle). Skallet er designet for brukervennlighet først.
  • Jeg er i prinsippet enig i brukervennligheten, men denne varianten mislykkes når du har et filnavn med hver ny linje inne. Dette kan lett skje ubemerket, for eksempel når du kopierer og limer inn en linje fra en pdf i et GUI, så du tenker bare å unngås patologiske filnavn .
  • Videre IMHO Det er ‘ det er lett å begynne å analysere ls, men det er mange fremtidige problemer. Ofte lager vi skript som vi vil bruke senere, når vi allerede vil glemme grensen deres … (det ‘ s menneskelig, det ‘ er vanlig). Jeg foreslo et find eksempel (med -exec og uten rør) selv om jeg anser det som et bedre (fordi rent skall) svarer cuonglm ‘ s en , solid og posix-kompatibel.
  • Dette er ganske mye det jeg ‘ d gjorde hvis jeg av en eller annen grunn ønsket å fjerne stripen .png suffiks fra en liste over filnavn.Jeg ville ikke ‘ ikke satt det i et skript; i stedet skrev jeg ‘ bare kommandoen ved shell-ledeteksten. Å gjøre det ville være en påminnelse om at jeg ‘ m antar » sunn » filnavn. Det er mange ting jeg ‘ vil gjøre i en engangs manuell kommando, når jeg gjerne tar antagelser om hva ‘ i den nåværende katalogen, at jeg sannsynligvis ikke ville ‘ ikke gjøre det i et skript som kan brukes på nytt i en annen sammenheng.

Svar

Jeg vil gå til basename (forutsatt GNU-implementering):

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

Kommentarer

  • Merk at hvis du vil bruke den i et rør, kan det være nyttig å bruke GNU-basenavn ‘ s -z (eller --zero) alternativ for å produsere NUL-atskilt (i stedet for nylinjeseparert ) output.

Svar

Du kan bare bruke BASH-kommandoer til å gjøre det (uten eksterne verktøy).

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

Dette er nyttig når du «er uten / usr / bin og fungerer fint for filnavn l like this.is.image.png og for alle utvidelser.

Svar

var ikke det nok?

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

eller generelt, dette

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

fjerner alle utvidelser

Kommentarer

  • Det var, men de andre løsningene fungerer også.
  • Alt Unix / Unix Like-system har (eller burde ha) sed installert ettersom det er et obligatorisk verktøy av standarden.
  • Faktisk, men ls gjør det uansett uten det alternativet når utgangen ikke er en terminal, som er tilfelle her.
  • Advarsel ls -1 | sed 's/\.[a-z]*//g' mislykkes hvis det er et filnavn som Image.png.jpg.png kutter hele tiden nøkkelen (.png). Under Unix er tillatt rare filnavn som The new art of working on .png?files and other formats.png der ? er en ny linjekarakter. Dessverre vil all løsningen som bare vil pipe / analysere ls -utdata påføre proble ms administrerer slike saker …
  • Hvorfor g kvalifiseringen? Du vil fjerne \.png bare på slutten av linjen, ikke hver gang den vises.

Svar

Det er ikke trygt å analysere ls eller å pipe find [ 1 , 2 ]

Det er ikke trygt å analysere (og til rør) utgangen av ls eller find, hovedsakelig fordi det er mulig å finne i filnavnene ikke vanlige tegn som newline , tab … Her vil en ren skallsyklus fungere [ cuonglm ] .
Selv find -kommandoen ikke piped med alternativet -exec fungerer:

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

Oppdateringer / notater : Du kan bruke find . til å søke selv etter de skjulte filene, eller find ./*.png å få bare de ikke skjulte. Med find *.png -exec ... kan du få problemer i tilfelle det var en fil med navnet .png fordi find vil få det som et alternativ. Du kan legge til -maxdepth 0 for å unngå å komme ned i kataloger som heter Dir_01.png, eller find ./*.png -prune -exec ... maks dybde er ikke tillatt (takk Stéphane). Hvis du vil unngå å liste disse katalogene, bør du legge til alternativet -type f (som også vil ekskludere andre typer ikke-vanlige filer). Ta en titt på man for et mer komplett panorama om alle tilgjengelige alternativer, og husk å sjekke når de er POSIX-kompatible, for bedre portabilitet.

Noen ord mer

Det kan for eksempel skje at kopiering av tittelen fra et dokument og liming inn i filnavnet, en eller flere nye linjer vil fullføres i selve filnavnet.Vi kan til og med være så uheldige at en tittel kan inneholde til og med nøkkelen vi må bruke like før en ny linje:

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

Hvis du vil teste, kan du lag filnavn som dette med kommandoene

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 enkle /bin/ls *png sender ut ? i stedet for ikke-utskrivbare tegn

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

I alle tilfeller vil du rør utgangen av ls eller find følgende kommando vil ikke ha noe hint å forstå hvis den nåværende linjen kommer fra et nytt filnavn eller hvis det følger et ny linje -tegn i presedens filnavn . Et stygt navn, men fortsatt et lovlig navn.

En skallsyklus med et skall Parameter-utvidelse, ${parameter%word}, i begge varianten med printf eller echo fungerer [ cuonglm ], [ Anthon1 ] .

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

Fra mannssiden av Shell Parameter-utvidelsen [ 3 ]

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

… resultatet av utvidelsen er verdien av parameteren med det korteste matchende mønsteret (% -saken) eller lengste matchende mønster (%% saken) slettet.

Kommentarer

  • Også resultatene av find kommando er litt variabel (for eksempel hvis det er en katalog som heter files.png)
  • Kjære @BroSlow, da jeg skrev svaret over I prøvde 13 (alle) andre varianter som var til stede i det øyeblikket, ved kommandolinje, i et skript, lansert som argument for en shellinnkallelse. Vennligst gjør det samme og fortell meg om de oppfører seg slik du forventer. Jeg gjorde testene mine med bash 4.3.11, dash 0.5.7-4, zsh (når det var nødvendig) 5.0.2. Les gjerne dette innlegget som legger til noe mer. Jeg er enig i merknaden om piping utgangen av find, for dette

, og jeg skrev i tittelen.:-).

  • Les wiki-en på nytt. Jeg tror fortsatt at du må pipe inn eksemplet ditt, siden det ‘ er det ‘ som blir diskutert her. Og for de fleste moderne versjoner av ls er det ingen ting overhodet når utdataene røres eller omdirigeres, men som nevnt i wiki fungerer det kanskje ikke for alle. De fleste vil bare sette inn ? i stedet for spesialtegn når utgangen sendes til terminalen. dvs. Gjør echo *.png | od -c og ls *.png | od -c. Nylinjeproblemet er ikke et problem med ls, det ‘ er et problem med en hvilken som helst kommando som ikke ‘ t null avsluttes over begge sider av røret.
  • printf "${f%.png}\n" er feil. Det første argumentet er formatet. Du bør ikke ‘ ikke bruke variable data der inne. Kan til og med sees som et DoS-sårbarhet (prøv med en %1000000000s.png -fil for eksempel).
  • Du ‘ d trenger find ./*.png -prune -exec... eller du ‘ d har problemer med filnavn som starter med - (og filer av typekatalog, merk at -maxdepth ikke er bærbar)
  • Svar

    Bruk rev:

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

    rev reverserer alle strenger (linjer); du klipper alt etter den første «.» og rev reverserer resten.

    Hvis du vil grep «alma»:

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

    Kommentarer

    • -1 er ikke nødvendig, som standard her.
    • Dette mislykkes dårlig i en fil som heter My.2016.Summer.Vacation.png
    • @DavidConrad min dårlige: / Jeg har korrigert til cut -f 2-
    • Nå fungerer den med den filen, men ennå ikke med en fil med .png og en ny linje like etter … Det anbefales å unngå å analysere ls fordi det elsker å gjemme overraskelsene godt … 🙂

    Svar

    Hvis jeg visste at katalogen bare hadde filer med .png som utvidelse, hadde jeg nettopp kjørt: ls | awk -F. "{print $1}"

    Dette returnerer det første «feltet» for alt der det er et filnavn. utvidelse.

    Eksempel:

    [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

    • Dessverre vil det mislykkes på alle filnavnene med mer enn ett ., som Image.1.png og til og med på de med ikke hyggelig navn , med spesialtegn inni. som den nye linjen eller den du vil bruke som (inngangs) opptaksseparator i awk, RS. Det anbefales å unngå å analysere ls -utgangen fordi den elsker å skjule et problem som vil oppstå når du ikke forventer. Du kan lese mer i referansen 1 eller 2 . BTW hyggelig ideen om å bruke awk … Jeg la noen eksempler i ett svar.
    • Det er sant, men gitt eksemplet fra Colin, ville det fungere helt fint. For å få det til å fungere for saken du foreslo, ville jeg ‘ sannsynligvis endre den til: [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 Ikke prøver å være vanskelig, men gitt Colin ‘ s behov, er jeg ‘ ikke sikker på hva problemet ville analyser ls.
    • beklager … Jeg skjønte bare at jeg ikke ‘ ikke viste katalogen med filene før jeg modifiserte utdataene til ‘ 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å unnslippe . i \. inne i sed -e 's/\.png$//', men så blir det et svar som bare er skrevet. 🙁 note2 du kan prøve å bruke awk med noe sånt som ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … men du vil ha alltid problemet som awk ikke kan vite om linjen ankommer følger eller ikke en ny linje i filnavnet. Jeg prøvde å si bedre i svaret mitt.
    • Takk Hastur, jeg savnet det :). Jeg dro også bruken av awk til fordel for sed i dette tilfellet.

    Svar

    i henhold til din kommentar «Jeg har en tekstfil hvor alle navnene er oppført uten utvidelsen. Jeg vil lage et PHP-skript som sammenligner tekstfilen med mappen for å se hvilken fil som mangler»:

    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 

    og omvendt:

    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$//"

    Er den mest nøyaktige metoden som fremhevet av @roaima. Uten de rømte \.png filene kalt a_png.png vil være oppført som: a_.

    Kommentarer

    • ved hjelp av ls -l, som du gjør, gir filopplysningene, det er ikke det OP spurte om.

    Svar

    En enkel skalllinje (ksh, bash eller zsh; ikke dash):

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

    En enkel funksjon (fra Ingen utvidelse):

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

    Eller en funksjon som fjerner hvilken som helst utvidelse gitt (png som standard):

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

    Bruk som:

    ne jpg 

    Hvis utgangen er en stjerne *, finnes det ingen fil med den utvidelsen.

    Svar

    Du kan prøve følgende feed awk resultatet av ls superatøren din er «.» og siden alle filene dine vil ha name.png skriver du ut den første kolonnen:
    ls | awk -F"." "{print $1}"

    Svar

    Hvis du har tilgang til sed, er dette bedre da det vil fjerne den siste filtypen, uansett hva den er (png, jpg, tiff, etc …)

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

    Kommentarer

    • Bryter for filnavn som this.is.a.dotty.txt. Prøv s/\.[^.]*$// i stedet.

    Legg igjen en kommentar

    Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *