' ls -1 ': jak vypsat názvy souborů bez přípony

ls -1 uvádí mé prvky takto:

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

Chci, aby byl uveden bez .png takto:

foo bar foobar ... 

(adresář obsahuje pouze .png soubory)

Může mi někdo říct, jak v tomto případě použít grep?

Účel: Mám textový soubor, kde jsou uvedena všechna jména bez rozšíření. Chci vytvořit skript, který porovná textový soubor se složkou a zjistí, který soubor chybí.

Komentáře

  • Chcete být opatrní taková žádost. Linux nemá přípony souborů. Linux obsahuje názvy souborů, které mohou nebo nemusí obsahovat .. Ačkoli konvence říká, že na konci pojmenovat své soubory .png, není důvod, proč ‚ nemůžu mít soubor png s názvem foo.zip nebo my.picture.20160518 nebo jen mypic.
  • @hymie I vím, ale všechny moje prvky v této složce jsou na konci pojmenovány .png.
  • Co ‚ je “ rozšíření „? To ‚ není součástí pojmenování souborů Unixu; je ‚ přenos z VMS / NT / Windows, ať už je to cokoli. A vy mladí také sejděte z mého trávníku. 🙂
  • Nech to ‚ s to nadhodnocovat. OS zachází s příponami jako s jednoduše součástí názvu souboru, ale věnuje jim pozornost spousta unixových programů, od kompilátoru po GUI. Tento koncept rozhodně není unixu cizí.
  • Obvykle se doporučuje vyhnout se analýze výstupu ls a k výstupu kanálu ls a find, hlavně kvůli možnosti vzniknout v newline,` char char v názvu souboru. Pokud je název souboru The new art of working on .png\NEWLINE files and other formats mnoho navrhovaného řešení způsobí problémy.

Odpovědět

Pro tuto úlohu potřebujete pouze shell.

POSIXly:

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

S zsh:

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

Komentáře

  • Tam ‚ není potřeba printf; echo ${f%.png} bude stačit.
  • @Conrad: použití echo nebude ‚ v některých případech správně fungovat, pokud název souboru začít s pomlčkou nebo obsahovat uniklé sekvence.
  • @DavidConrad: Viz také unix.stackexchange.com/a/65819/38906
  • @DavidConrad Navíc se domnívám, že je integrován printf, stejně jako echo, někdo mě opraví, pokud se ‚ mýlím

Odpověď

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

Příkaz sed odstraní (tj. nahrazuje prázdným řetězcem) jakýkoli řetězec .png nalezený na konci z název souboru.

. je uvozeno jako \., takže je interpretováno sed jako doslovný . znak spíše než regexp . (což znamená shodu s jakýmkoli aracter). $ je kotva konce řádku, takže neodpovídá .png uprostřed názvu souboru.

Komentáře

  • Myslím, že OP chce jakékoli rozšíření zbavené, ale pravděpodobně pouze “ poslední „. Takže možná upravte svou jinak dobrou odpověď pomocí: sed 's/\.[^.]*$//'
  • ano, ten regexp by v takovém případě … ale pokud to OP chce, měli by to říci, místo aby konkrétně řekli, že “ chtějí, aby to bylo uvedeno bez .png “
  • -1 není nutné, je zde výchozí.
  • @jlliagre Souhlasím s tím, že -1. Je to ‚ pouze výchozí hodnota, když je zapnutá roura, což je pro některé skryté překvapení. Takže její výslovné použití rozumím. Dělám to také ve svých skriptech, abych věděl, jaký druh o utput I ‚ očekávám.
  • Varování V případě názvu souboru s klíčem (.png) před znakem nového řádku vymažete i ten .png a nejen ten poslední. Je lepší vyhnout se analýze výstupu ls, vyhrazuje si často dobře skrytá překvapení … (některá slova a odkazy více v odpovědi).

Odpověď

Pokud chcete použít pouze bash:

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

Při hledání shody byste měli sáhnout po grep, ne po odstranění / nahrazení toho sed je vhodnější:

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

Jakmile se rozhodnete pro vytvoření pořádku ve svých souborech PNG, musíte vytvořit nějaké podadresáře, které můžete snadno změnit na:

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

Komentáře

  • ls -1 | sed ‚ s / .png // ‚ funguje skvěle. Děkujeme!
  • Řešení find piped do sed může představovat určité problémy, pokud soubor s klíčem (.png) najdete jako součást jména a těsně před znakem nového řádku. Je lepší vyhnout se propojení a analýze výstupu find nebo ls, vyhrazuje si často dobře skrytá překvapení … (některá slova a odkazy více v odpovědi).
  • Pravděpodobně v posledním příkladu nahraďte find něčím jako echo. Není jasné, k jakému účelu find slouží a výsledky závisí na struktuře adresářů (tj. Pokud máte adresář files.png)
  • @BroSlow Aktualizováno na něco rozumnějšího.

Odpověď

Další velmi podobná odpověď (překvapilo mě to konkrétní varianta dosud nebyla uvedena) je:

ls | sed -n "s/\.png$//p" 
  • Nepotřebujete -1 možnost ls, protože ls předpokládá, že pokud standardní výstup není terminál (v tomto případě je to potrubí).
  • možnost -n sed znamená, že ve výchozím nastavení nebude řádek vytištěn,
  • možnost /p na konci substituce znamená „… a vytiskněte tento řádek, pokud došlo k substituci“.

Síť výsledkem je tisk pouze těch řádků, které končí na .png s odstraněno. To znamená, že se také postará o mírné zobecnění otázky OP, kde adresář neobsahuje pouze .png soubory.

sed -n technika je často užitečná v případech, kdy byste jinak mohli použít grep + sed.

Komentáře

  • Líbí se mi, jak se péče kdysi jste psali svou odpověď. Toto řešení způsobí problémy s názvy souborů včetně nových řádků , nevytiskne první část názvu. Ještě více, pokud je to s klíčem hnusnější (.png) před znakem nového řádku: v takovém případě tuto část vytisknete bez png a nevymažete pouze poslední část. Často se doporučuje vyhnout se analýze (a směrování) výstupu ls protože problémy lze skrýt právě tam, na které nemyslíte …
  • @Hastur Vy ‚ napravíte , v zásadě a slavná stránka o don ‚ t parse ls uvádí další problémy (a řešení) při předávání patologických názvů souborů. Nejlepší způsob manipulace je ale vyhnout se patologickým názvům souborů (doh!); a pokud můžete ‚ t nebo pokud musíte být proti nim robustní, použijte buď find nebo – možná lepší – pro jejich správu použijte výkonnější jazyk než sh (skutečnost, že sh může dělat vše ‚ to neznamená, že je to ‚ nejlepší volba). Shell je navržen nejprve pro použitelnost.
  • V zásadě souhlasím s použitelností, ale tato varianta selže, když máte název souboru s každým novým řádkem uvnitř. K tomu může snadno dojít nepozorovaně, například když zkopírujete a vložíte řádek z souboru PDF do grafického uživatelského rozhraní, takže si myslíte, že se vyhnete pouze patologickým názvům souborů .
  • Navíc IMHO ‚ Je snadné začít analyzovat ls, ale jde o budoucí problémy. Často vytváříme skripty které použijeme později, až už zapomeneme na jejich limit … (je ‚ s člověkem, je ‚ obvyklý). Navrhl jsem příklad find (s -exec a bez potrubí) i když považuji za lepší (protože čistou skořápku) odpověď na cuonglm ‚ s , pevnou a vyhovující.
  • To je do značné míry to, co ‚ d dělám, pokud bych z nějakého důvodu chtěl odstranit .png přípona ze seznamu názvů souborů.Nerad bych to ‚ vložil do skriptu; místo toho ‚ d stačí zadat příkaz do příkazového řádku. Bylo by to připomenutí, že ‚ m předpokládám “ sane “ názvy souborů. Existuje spousta věcí, které ‚ provedu v jednorázovém manuálním příkazu, když mohu volně předpokládat, co ‚ s v aktuálním adresáři, který bych pravděpodobně ‚ nedělal ve skriptu, který by mohl být znovu použit v jiném kontextu.

Odpověď

Chtěl bych basename (za předpokladu implementace GNU):

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

Komentáře

  • Upozorňujeme, že pokud jej chcete použít v kanálu, může být užitečné použít GNU basename ‚ s -z (nebo --zero) možnost produkovat NUL-oddělené (místo nového řádku oddělené) ) výstup.

Odpověď

K tomu můžete použít pouze příkazy BASH (bez externích nástrojů).

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

To je užitečné, když nemáte / usr / bin a funguje dobře pro názvy souborů l ike this.is.image.png a pro všechna rozšíření.

Odpověď

to nestačilo?

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

nebo obecně to

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

odstraní všechna rozšíření

Komentáře

  • Bylo, ale fungují i ostatní řešení.
  • Všechny systémy Unix / Unix Like mají (nebo by měly mít) sed nainstalován, protože se jedná o povinný nástroj standardem.
  • Skutečně, ale ls to dělá stejně bez této možnosti, když jeho výstup není terminál, což je případ zde.
  • Varování ls -1 | sed 's/\.[a-z]*//g' se nezdaří, pokud existuje název, který Image.png.jpg.png po celou dobu klíč (.png). V systému Unix jsou povoleny podivné názvy souborů jako The new art of working on .png?files and other formats.png, kde ? je znak nového řádku. Bohužel všechna řešení, která budou jednoduše spojovat / analyzovat výstup ls, proběhnou v proble ms spravující takové případy …
  • Proč g kvalifikátor? Chcete odstranit \.png pouze na konci řádku, ne pokaždé, když se zobrazí.

Odpovědět

Není bezpečné analyzovat ls nebo pipovat find [ 1 , 2 ]

Není bezpečné analyzovat (a do kanálu) výstup ls nebo find, hlavně proto, že je možné najít v názvech souborů neobvyklé znaky jako nový řádek , karta … Zde bude fungovat čistý cyklus prostředí [ cuonglm ] .
I find příkaz není pipedován s možností -exec bude fungovat:

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

Aktualizace / poznámky : Pomocí find . můžete vyhledávat i skryté soubory nebo find ./*.png získat jen ty neskrývané. S find *.png -exec ... můžete mít problém v případě, že byl přítomen soubor s názvem .png, protože find jej získá jako volitelnou možnost. Můžete přidat -maxdepth 0, abyste se vyhnuli sestupu do adresářů s názvem Dir_01.png nebo find ./*.png -prune -exec ... když maxdepth není povolena (díky Stéphane). Pokud se chcete těmto adresářům vyhnout, měli byste přidat možnost -type f (která by také vyloučila jiné typy nepravidelných souborů). Podívejte se do man a získejte ucelenější panorama všech dostupných možností. Nezapomeňte zkontrolovat, zda jsou kompatibilní s POSIXem, abyste získali lepší přenositelnost.

Některá slova více

Může se například stát, že kopírováním názvu z dokumentu a vložením do názvu souboru jeden nebo více nových řádků skončí v samotném názvu souboru.Můžeme mít dokonce takovou smůlu, že název může obsahovat i klíč, který musíme použít těsně před novým řádkem:

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

Chcete-li otestovat, můžete pomocí příkazů vytvořte podobné názvy souborů

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" 

Jednoduchý /bin/ls *png vypíše ? místo netisknutelných znaků

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

Ve všech případech, kdy potrubí výstup z ls nebo find následující příkaz nebude mít žádnou nápovědu k pochopení pokud současný řádek pochází z nového názvu souboru nebo pokud následuje za znakem nový řádek v předchozím názvu souboru . Skutečně ošklivé jméno, ale stále legální.

Cyklus prostředí s rozšířením parametrů, ${parameter%word} v obou varianta s printf nebo echo bude fungovat [ cuonglm ], [ Anthon1 ] .

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

Z manuálové stránky rozšíření parametrů Shell [ 3 ]

$ {parametr% word}
$ {parametr %% word}

… výsledkem expanze je hodnota parametru s nejkratším shodným vzorem (případ %) nebo nejdelší shodný vzor (případ %%) smazán.

Komentáře

  • Také výsledky vašich find jsou bitové proměnné (například pokud existuje adresář s názvem files.png)
  • Vážený @BroSlow, když jsem napsal odpověď výše I vyzkoušeli 13 (všechny) z ostatních variant přítomných v daném okamžiku, pomocí příkazového řádku, ve skriptu, spuštěného jako argument vyvolání shellu. Udělejte prosím totéž a řekněte mi, jestli se chovají tak, jak očekáváte. Provedl jsem testy pomocí bash 4.3.11, pomlčky 0.5.7-4, zsh (v případě potřeby) 5.0.2. Můžete si přečíst tento příspěvek , který přidává něco navíc. Souhlasím s poznámkou piping výstupu find, k tomu jsem výslovně navrhl -exec a já jsem napsal do názvu. :-).
  • Znovu si přečtěte wiki. Stále si myslím, že ve svém příkladu musíte použít potrubí, protože o tom ‚ se diskutuje zde ‚. A pro většinu moderních verzí ls neexistuje žádný problém, když je výstup směrován nebo přesměrován, ale jak je uvedeno ve wiki, nemusí to fungovat pro všechny. Většina z nich vloží pouze ? místo zvláštních znaků, když je výstup odeslán na terminál. tj. proveďte echo *.png | od -c a ls *.png | od -c. Problém nového řádku není problémem ls, ‚ je problémem s jakýmkoli příkazem, který ‚ t null končí na obou stranách potrubí.
  • printf "${f%.png}\n" se mýlí. Prvním argumentem je formát, neměli byste tam ‚ používat proměnná data. Může být dokonce viděn jako chyba zabezpečení DoS (zkuste například soubor %1000000000s.png).
  • Vy ‚ d potřebujete find ./*.png -prune -exec... nebo vy ‚ d máte problémy s názvy souborů začínajících - (a soubory zadejte adresář, nezapomeňte, že -maxdepth není přenosný)

Odpověď

Použití rev:

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

rev obrátí všechny řetězce (řádky); po prvním „.“ a rev re-obrátí zbytek.

Pokud chcete grep „alma“:

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

Komentáře

  • -1 není nutný, je zde výchozí.
  • Toto selže špatně v souboru s názvem My.2016.Summer.Vacation.png
  • @DavidConrad můj špatný: / Opravil jsem cut -f 2-
  • Nyní s tímto souborem funguje, ale ještě ne se souborem s .png a novým řádkem hned po … Doporučuje se vyhnout se analýze ls protože ráda dobře skrývá překvapení … 🙂

odpověď

Kdybych věděl, že adresář obsahuje pouze soubory s příponou .png, právě bych spustil: ls | awk -F. "{print $1}"

Tím se vrátí první „pole“ pro cokoli, kde je název souboru. přípona.

Příklad:

[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 

Komentáře

  • Bohužel selže u všech názvy souborů s více než jedním ., jako Image.1.png a dokonce i na ty, které nemají ne hezké jména se zvláštními znaky uvnitř. jako nový řádek nebo ten, který použijete jako (vstupní) oddělovač záznamů v awk, RS. Doporučuje se vyhnout se analýze výstupu ls, protože rád skrývá problém, který nastane, když ho nebudete očekávat. Další informace najdete v těchto referencích 1 nebo 2 . BTW pěkný nápad použít awk … V jedné odpovědi jsem uvedl několik příkladů.
  • Je to pravda, vzhledem k tomu, že vzorek poskytnutý Colinem by to fungovalo dobře. Aby to fungovalo pro případ, který jste navrhli, ‚ d to pravděpodobně změním na: [rsingh @ rule51 TESTDIR] $ ls | sed -e ‚ s / .png $ // ‚ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny co .a.png.filename Nesnažím se být obtížný, ale vzhledem k Colinově ‚ potřebě si nejsem jistý, co by problém způsobil analyzovat ls.
  • omlouvám se … právě jsem si uvědomil, že jsem ‚ nezobrazil adresář se soubory před sed úpravou výstupu ‚ 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 co .a.png.filename
  • note1 musíte uniknout . v \. uvnitř sed -e 's/\.png$//', ale stane se právě napsanou odpovědí. 🙁 note2 můžete zkusit použít awk s něčím jako ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … ale budete mít problém, který awk nemůže vědět, zda linka přichází, sleduje nový řádek uvnitř názvu souboru. Snažil jsem se ve své odpovědi říci lépe.
  • Díky Hastur, to mi chybělo :). V tomto případě jsem také upustil od použití awk ve prospěch sed.

Odpovědět

podle vašeho komentář „Mám textový soubor, kde jsou uvedena všechna jména bez přípony. Chci vytvořit skript PHP, který porovná textový soubor se složkou a zjistí, který soubor chybí“:

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 

a naopak:

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) 

odpověď

ls -l | sed "s/\.png$//"

Je to nejpřesnější metoda, jak ji zdůrazňuje @roaima. Bez uniklých \.png souborů s názvem a_png.png by byly uvedeny jako: a_.

Komentáře

  • pomocí ls -l, stejně jako vy, uvedete podrobnosti souboru, což OP neptá o.

Odpověď

Jednoduchá linka shellu (ksh, bash nebo zsh; ne pomlčka):

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

Jednoduchá funkce (bez rozšíření):

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

Nebo funkce, která odstraní jakékoli dané rozšíření (ve výchozím nastavení png):

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

Použít jako:

ne jpg 

Pokud je výstupem hvězdička *, žádný soubor s touto příponou neexistuje.

Odpovědět

Můžete zkusit následující zdroj, jehož výstupem je, že váš superator je „.“ a protože všechny vaše soubory budou mít name.png, vytisknete první sloupec:
ls | awk -F"." "{print $1}"

Odpovědět

Pokud máte přístup k sed, je to lepší, protože odstraní poslední příponu souboru, bez ohledu na to, co to je (png, jpg, tiff atd.)

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

Komentáře

  • Přerušení pro názvy souborů jako this.is.a.dotty.txt. Zkuste místo toho s/\.[^.]*$//.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *