' ls -1 ': cómo enumerar nombres de archivos sin extensión

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

  • Debes tener cuidado con una solicitud como esta. Linux no tiene extensiones de nombre de archivo. Linux tiene nombres de archivo que pueden incluir o no un . 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 llamado foo.zip o my.picture.20160518 o simplemente mypic.
  • @hymie I lo sé, pero todos mis elementos en esa carpeta se nombran con .png al final.
  • ¿Qué ‘ es un » extensión «? Eso ‘ no es parte del nombre de archivo Unix; es ‘ remanente de VMS / NT / Windows lo que sea. Y ustedes, jóvenes, salgan de mi césped también. 🙂
  • Dejemos que ‘ s no exagere esto. El sistema operativo trata las extensiones simplemente como parte del nombre del archivo, pero muchos programas Unix les prestan atención, desde el compilador hasta la GUI. El concepto ciertamente no es ajeno a Unix.
  • Por lo general, se sugiere evitar analizar la salida de ls y canalizar la salida de ls y find, principalmente debido a la posibilidad de incurrir en newline,` tab char en el nombre del archivo. Si el nombre del archivo es The new art of working on .png\NEWLINE files and other formats muchas de las soluciones propuestas crearán problemas.

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 a sed 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 de find o ls, a menudo se reserva sorpresas bien escondidas … (algunas palabras y referencias más en la respuesta).
  • Probablemente reemplace find con algo como echo en el último ejemplo. No está claro para qué sirve find allí y los resultados dependen de la estructura del directorio (es decir, si tiene un directorio files.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 a ls, ya que ls asume que si la salida estándar no es «una terminal (es» una tubería, en este caso).
  • la opción -n para sed 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 de ls 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 que sh para administrarlos (el hecho de que sh 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 un find 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 como Image.png.jpg.png cortando todo el tiempo la clave (.png). En Unix se permiten nombres de archivo extraños como The 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 de ls 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 llamado files.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 de find, 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, haz echo *.png | od -c y ls *.png | od -c. El problema de la nueva línea no es un problema con ls, 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 analizar ls 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 ., como Image.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) en awk, RS. Se sugiere evitar analizar la salida ls 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 de sed -e 's/\.png$//', pero se convierte en una respuesta recién escrita. 🙁 note2 puede intentar usar awk con algo como ls | 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. Pruebe s/\.[^.]*$// en su lugar.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *