ls -1
enumera mis elementos así:
foo.png bar.png foobar.png ...
Lo quiero en la lista sin .png
así:
foo bar foobar ...
(el directorio solo contiene .png
archivos)
¿Alguien puede decirme cómo usar grep
en este caso?
Propósito: Tengo un archivo de texto donde todos los nombres se enumeran sin el extensión. Quiero hacer un script que compare el archivo de texto con la carpeta para ver qué archivo falta.
Comentarios
Respuesta
Solo necesita el shell para este trabajo.
POSIXly:
for f in *.png; do printf "%s\n" "${f%.png}" done
Con zsh
:
print -rl -- *.png(:r)
Comentarios
- Hay ‘ s no es necesario
printf
;echo ${f%.png}
será suficiente. - @Conrad: el uso de echo no ‘ no funcionará correctamente en algunos casos, si el nombre del archivo comience con un guión o contenga secuencias de escape.
- @DavidConrad: Consulte también unix.stackexchange.com/a/65819/38906
- @DavidConrad Además, creo que printf está integrado, al igual que echo, alguien me corrija si ‘ me equivoco
Responder
ls -1 | sed -e "s/\.png$//"
El comando sed
elimina (es decir, reemplaza por la cadena vacía) cualquier cadena .png
encontrada en el final de un nombre de archivo.
El .
se escapa como \.
para que sea interpretado por sed
como un carácter .
literal en lugar de la expresión regular .
(que significa que coincide con cualquier ch personaje). El $
es el ancla de fin de línea, por lo que no «coincide con .png
en el medio de un nombre de archivo.
Comentarios
- Creo que el OP quiere cualquier extensión eliminada, pero probablemente solo » último «. Entonces, tal vez modifique su buena respuesta con:
sed 's/\.[^.]*$//'
- sí, esa expresión regular funciona en ese caso … pero si el OP quiere eso, deberían decirlo en lugar de decir específicamente que » lo quieren en la lista sin el .png »
- El
-1
no es necesario, siendo el predeterminado aquí. - @jlliagre Estoy de acuerdo con cas que el
-1
debe especificarse. Es ‘ solo el valor predeterminado cuando la tubería está encendida, lo cual es una sorpresa oculta para algunos. Por lo tanto, hacerlo explícito ayuda comprensión. También hago esto en mis guiones para saber qué tipo de utput I ‘ estoy esperando. - Advertencia En el caso de un nombre de archivo con la clave (
.png
) antes de un carácter de nueva línea, borrará incluso ese.png
y no solo el último. Es mejor evitar canalizar y analizar la salida de ls, a menudo se reserva sorpresas bien escondidas … (algunas palabras y referencias más en la respuesta).
Responder
Si solo desea utilizar bash:
for i in *; do echo "${i%.png}"; done
Debe buscar grep
cuando intente encontrar coincidencias, no para eliminar / sustituir ese sed
más apropiado:
find . -maxdepth 1 -name "*.png" | sed "s/\.png$//"
Una vez que decida que necesita crear algunos subdirectorios para poner orden en sus archivos PNG, puede cambiarlo fácilmente a:
find . -name "*.png" | sed "s/\.png$//"
Comentarios
- ls -1 | sed ‘ s / .png // ‘ funciona muy bien. ¡Gracias!
- La solución
find
canalizada ased
puede presentar algunos problemas si encuentra un archivo con la clave (.png
) como parte del nombre y justo antes de un carácter de nueva línea. Es mejor evitar canalizar y analizar la salida defind
ols
, a menudo se reserva sorpresas bien escondidas … (algunas palabras y referencias más en la respuesta). - Probablemente reemplace
find
con algo comoecho
en el último ejemplo. No está claro para qué sirvefind
allí y los resultados dependen de la estructura del directorio (es decir, si tiene un directoriofiles.png
) - @BroSlow Actualizado a algo más sensato.
Respuesta
Otra respuesta muy similar (me sorprende esto una variante en particular no ha aparecido todavía) es:
ls | sed -n "s/\.png$//p"
- No necesita el
-1
opción als
, ya quels
asume que si la salida estándar no es «una terminal (es» una tubería, en este caso). - la opción
-n
parased
significa no «imprimir la línea por defecto - la opción
/p
al final de la sustitución significa … e imprima esta línea si se realizó una sustitución.
La red El efecto de eso es imprimir solo aquellas líneas que terminan en .png
, con la eliminado. Es decir, esto también responde a la ligera generalización de la pregunta del OP, donde el directorio no contiene solo archivos .png
.
El suele ser útil en los casos en los que podría utilizar grep + sed.
Comentarios
- Me gusta el cuidado que solía escribir su respuesta. Esta solución presentará problemas con los nombres de archivo que incluyen líneas nuevas , no imprimirá la primera parte del nombre. Más aún si es uno más desagradable con la clave (
.png
) antes del carácter de nueva línea: en ese caso, imprimirá esa parte sin png, sin borrar solo la última parte. A menudo se sugiere evitar analizar (y canalizar) la salida dels
porque los problemas pueden ocultarse justo donde no estás pensando … - @Hastur Tú ‘ estás en lo correcto , en principio, y la famosa página sobre don ‘ t parse ls enumera más problemas (y soluciones) al administrar nombres de archivos patológicos. Pero la mejor forma de manejar eso es evitar tener nombres de archivo patológicos (¡doh!); y si puede ‘ t, o si debe ser robusto contra ellos, utilice
find
o – posiblemente mejor – use un lenguaje más poderoso quesh
para administrarlos (el hecho de quesh
pueda todo no ‘ significa que ‘ es la mejor opción en cada caso). El shell está diseñado para la usabilidad primero. - Estoy de acuerdo, en principio, sobre la usabilidad, pero esta variante falla cuando tienes un nombre de archivo con cada nueva línea adentro. Esto puede pasar fácilmente desapercibido, por ejemplo, cuando copia y pega una línea de un pdf en una GUI, por lo que solo piensa que debe evitarse nombres de archivo patológicos.
- Además, en mi humilde opinión Es ‘ fácil comenzar a analizar
ls
, pero hay problemas en el futuro. A menudo hacemos scripts que usaremos más adelante, cuando ya olvidemos su límite … (es ‘ es humano, ‘ es habitual). propuse unfind
ejemplo (con-exec
y sin tubería) incluso si considero una respuesta mejor (porque pura shell) la cuonglm ‘ s one , sólida y compatible con posix. - Esto es más o menos lo que ‘ haría si, por alguna razón, quisiera quitar la tira
.png
sufijo de una lista de nombres de archivos.Yo no ‘ t lo pondría en un script; en su lugar, ‘ d simplemente escribo el comando en la línea de comandos. Hacerlo sería un recordatorio de que ‘ m supongo » sano » nombres de archivo. Hay muchas cosas que ‘ haré en un comando manual único, cuando me sienta libre de hacer suposiciones sobre lo que ‘ s en el directorio actual, que probablemente no haría ‘ en un script que podría reutilizarse en algún otro contexto.
Respuesta
Optaría por basename
(asumiendo la implementación de GNU):
basename --suffix=.png -- *.png
Comentarios
- Tenga en cuenta que si desea utilizarlo en una tubería, puede resultarle útil utilizar GNU basename ‘ s
-z
(o--zero
) opción para producir valores separados por NUL (en lugar de por saltos de línea ).
Respuesta
Puede usar solo comandos BASH para hacer eso (sin herramientas externas).
for file in *; do echo "${file%.*}"; done
Esto es útil cuando «no tiene / usr / bin y funciona bien para nombres de archivo l como this.is.image.png y para todas las extensiones.
Respuesta
¿No fue suficiente?
ls -1 | sed "s/\.png//g"
o en general, esto
ls -1 | sed "s/\.[a-z]*//g"
eliminará todas las extensiones
Comentarios
- Lo fue, pero las otras soluciones también funcionan.
- Todos los sistemas Unix / Unix Like tienen (o deberían tener)
sed
instalado ya que es una utilidad obligatoria por el estándar. - De hecho, pero
ls
lo hace de todos modos sin esa opción cuando su salida no es una terminal, que es el caso aquí. - Advertencia
ls -1 | sed 's/\.[a-z]*//g'
fallará si hay un nombre de archivo comoImage.png.jpg.png
cortando todo el tiempo la clave (.png
). En Unix se permiten nombres de archivo extraños comoThe new art of working on .png?files and other formats.png
donde?
es un carácter de nueva línea. Desafortunadamente, toda la solución que simplemente canalizará / analizará la salida dels
generará problemas ms manejando tales casos … - ¿Por qué el calificador
g
? Desea eliminar\.png
solo al final de la línea, no cada vez que aparece.
Respuesta
No es seguro analizar ls
o canalizar find
[ 1 , 2 ]
No es seguro analizar (y canalizar) la salida de ls
o find
, principalmente porque es posible encontrar en los nombres de archivo caracteres no habituales como la nueva línea , la pestaña … Aquí un ciclo de shell puro funcionará [ cuonglm ] .
Incluso el find
comando no canalizado con la opción -exec
funcionará:
find ./*.png -exec basename {} .png \;
Actualizaciones / Notas : puede usar find .
para buscar incluso los archivos ocultos, o find ./*.png
para obtener solo los no ocultos. Con find *.png -exec ...
puede tener problemas en el caso de que estuviera presente un archivo llamado .png
porque find lo obtendrá como una opción. Puede agregar -maxdepth 0
para evitar descender en directorios denominados Dir_01.png
o find ./*.png -prune -exec ...
cuando maxdepth no está permitido (gracias Stéphane). Si desea evitar enumerar esos directorios, debe agregar la opción -type f
(que también excluiría otros tipos de archivos no regulares). Échale un vistazo a la man
para obtener un panorama más completo de todas las opciones disponibles, y recuerda comprobar cuándo son compatibles con POSIX, para una mejor portabilidad.
Algunas palabras más
Puede suceder, por ejemplo, que al copiar el título de un documento y pegarlo en el nombre del archivo, una o más líneas nuevas terminen en el nombre del archivo.Incluso podemos tener la mala suerte de que un título pueda contener incluso la clave que tenemos que usar justo antes de una nueva línea:
The new art of working on .png files and other formats.
Si quieres probar, puedes cree nombres de archivo como este con los comandos
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"
El simple /bin/ls *png
generará ?
en lugar de los caracteres no imprimibles
A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png
En todos los casos en los que canalice la salida de ls
o find
el siguiente comando no tendrá ninguna pista para entender si la línea actual proviene de un nuevo nombre de archivo o si sigue un carácter de nueva línea en el nombre de archivo anterior. Un nombre desagradable de hecho, pero aún legal.
Un ciclo de shell con una expansión de parámetros de shell, ${parameter%word}
, en ambos la variante con printf
o echo
funcionará [ cuonglm ], [ Anthon1 ] .
for f in *.png; do printf "%s\n" "${f%.png}" ; done
Desde la página de manual de la expansión de parámetros de shell [ 3 ]
$ {parámetro% palabra}
$ {parámetro %% palabra}… el resultado de la expansión es el valor del parámetro con el patrón de coincidencia más corto (el caso %) o el patrón de coincidencia más largo (el caso %%) eliminado.
Comentarios
- También los resultados de su
find
son una variable de bits (por ejemplo, si hay un directorio llamadofiles.png
) - Estimado @BroSlow, cuando escribí la respuesta anterior I Intenté 13 (todas) de las otras variantes presentes en ese momento, por línea de comando, en un script, lanzado como argumento de una invocación de shell. Por favor, haga lo mismo y dígame si se comportan de la manera que espera. Hice mis pruebas con
bash 4.3.11
, dash 0.5.7-4, zsh (cuando sea necesario) 5.0.2. Siéntase libre de leer esta publicación que agrega algo más. Estoy de acuerdo con la nota de canalizar la salida defind
, por esto sugerí expresamente-exec
, y escribí en el título.:-)
. - Vuelva a leer la wiki. Sigo pensando que necesitas incluir tu ejemplo, ya que ‘ es lo que ‘ se está discutiendo aquí. Y para la mayoría de las versiones modernas de
ls
no hay ningún problema cuando la salida es canalizada o redirigida, pero como se menciona en wiki puede que no funcione para todos. La mayoría solo insertará?
en lugar de caracteres especiales cuando la salida se envíe a la terminal. es decir, hazecho *.png | od -c
yls *.png | od -c
. El problema de la nueva línea no es un problema conls
, es ‘ un problema con cualquier comando que no ‘ t nulo termina en ambos lados de la tubería. -
printf "${f%.png}\n"
es incorrecto. El primer argumento es el formato, no debe ‘ t usar datos variables allí. Incluso puede verse como una vulnerabilidad DoS (intente con un archivo%1000000000s.png
por ejemplo). - Usted ‘ d necesita
find ./*.png -prune -exec...
o ‘ d tiene problemas con nombres de archivo que comienzan con-
(y archivos de tipo directorio, tenga en cuenta que-maxdepth
no es portátil)
Respuesta
Use rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
invierte todos los cadenas (líneas); se corta todo después del primer «.» y rev invierte el remanente.
Si desea grep
«alma»:
ls -1 | rev | cut -f 2- -d "." | rev | grep "alma"
Comentarios
- El
-1
no es necesario, siendo el predeterminado aquí. - Este falla mal en un archivo llamado
My.2016.Summer.Vacation.png
- @DavidConrad mi error: / He corregido a
cut -f 2-
- Ahora funciona con ese archivo, pero todavía no con un archivo con
.png
y una nueva línea justo después de … Se sugiere evitar analizarls
porque le encanta esconder bien las sorpresas … 🙂
Responder
Si hubiera sabido que el directorio solo tenía archivos con .png como extensión, simplemente habría ejecutado: ls | awk -F. "{print $1}"
Esto devolverá el primer «campo» para cualquier cosa donde haya un nombre de archivo.extensión.
Ejemplo:
[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
Comentarios
- Desafortunadamente, fallará en todos los nombres de archivo con más de un
.
, comoImage.1.png
e incluso en los que tienen no agradables nombres , con caracteres especiales en su interior. como el salto de línea o el que usará como separador de registros (entrada) enawk
,RS
. Se sugiere evitar analizar la salidals
porque le encanta ocultar los problemas que surgirán cuando no los espera. Puede leer más en esas referencias 1 o 2 . Por cierto, es buena la idea de usar awk … Puse algunos ejemplos en una respuesta. - Cierto, sin embargo, dado el ejemplo proporcionado por Colin, funcionaría bien. Para que funcione en el caso que sugirió, ‘ probablemente lo cambie a: [rsingh @ rule51 TESTDIR] $ ls | sed -e ‘ s / .png $ // ‘ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny qué .a.png.filename No intento ser difícil, pero dada la necesidad de Colin ‘, yo ‘ no estoy seguro de cuál sería el problema estar analizando ls.
- lo siento … me acabo de dar cuenta de que no ‘ t mostrar el directorio con los archivos antes de sed modificando la salida de ‘ 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 qué .a.png.filename
- nota1 necesita escapar del
.
en\.
dentro desed -e 's/\.png$//'
, pero se convierte en una respuesta recién escrita. 🙁 note2 puede intentar usarawk
con algo comols | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}'
… pero tendrá Siempre el problema de que awk no puede saber si la línea está llegando es seguir o no una nueva línea dentro del nombre del archivo. Intenté decir mejor en mi respuesta. - Gracias Hastur, me perdí eso :). Además, abandoné el uso de awk a favor de sed en este caso.
Respuesta
de acuerdo con su comentar «Tengo un archivo de texto donde se enumeran todos los nombres sin la extensión. Quiero hacer un script PHP que compare el archivo de texto con la carpeta para ver qué archivo falta»:
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
y al revés:
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)
Responder
ls -l | sed "s/\.png$//"
Es el método más preciso como lo destaca @roaima. Sin los archivos de escape \.png
llamados a_png.png
aparecerían como: a_
.
Comentarios
- usando
ls -l
, mientras lo haces, da los detalles del archivo, eso no es lo que pidió el OP about.
Respuesta
Una línea de shell simple (ksh, bash o zsh; no guión):
set -- *.png; printf "%s\n" "${@%.png}"
Una función simple (de Sin extensión):
ne(){ set -- *.png; printf "%s\n" "${@%.png}"; }
O una función que elimina cualquier extensión dada (png por defecto):
ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; }
Usar como:
ne jpg
Si el resultado es un asterisco *
, no existe ningún archivo con esa extensión.
Respuesta
Puede probar el siguiente feed awk, la salida de ls su superador es «.» y dado que todos sus archivos tendrán name.png, imprima la primera columna:
ls | awk -F"." "{print $1}"
Respuesta
Si tiene acceso a sed, esto es mejor ya que eliminará la última extensión del archivo, sin importar cuál sea (png, jpg, tiff, etc …)
ls | sed -e "s/\..*$//"
Comentarios
- Saltos para nombres de archivo como
this.is.a.dotty.txt
. Pruebes/\.[^.]*$//
en su lugar.
.
en ellos. Aunque la convención dice que asigne un nombre a sus archivos con.png
al final, no hay ninguna razón por la que no pueda ‘ tener un archivo png llamadofoo.zip
omy.picture.20160518
o simplementemypic
.ls
y canalizar la salida dels
yfind
, principalmente debido a la posibilidad de incurrir ennewline
,` tab char en el nombre del archivo. Si el nombre del archivo esThe new art of working on .png\NEWLINE files and other formats
muchas de las soluciones propuestas crearán problemas.