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
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 dosed
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ýstupufind
nebols
, 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 jakoecho
. Není jasné, k jakému účelufind
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žnostls
, protožels
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ýstupuls
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, žesh
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říkladfind
(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ů jakoThe 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ýstupls
, 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ázvemfiles.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ýstupufind
, 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ďteecho *.png | od -c
als *.png | od -c
. Problém nového řádku není problémemls
, ‚ 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ýzels
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
.
, jakoImage.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ů vawk
,RS
. Doporučuje se vyhnout se analýze výstupuls
, 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žítawk
s něčím jakols | 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 tohos/\.[^.]*$//
.
.
. Ačkoli konvence říká, že na konci pojmenovat své soubory.png
, není důvod, proč ‚ nemůžu mít soubor png s názvemfoo.zip
nebomy.picture.20160518
nebo jenmypic
.ls
a k výstupu kanáluls
afind
, hlavně kvůli možnosti vzniknout vnewline
,` char char v názvu souboru. Pokud je název souboruThe new art of working on .png\NEWLINE files and other formats
mnoho navrhovaného řešení způsobí problémy.