Tengo algunos archivos que me gustaría borrar el último caracter de fin de línea si es que el último carácter en un archivo. od -c me muestra que el comando ejecutar no guarda el archivo con un punto final de la línea nueva:

0013600   n   t  >  \n

Yo he probado un par de trucos con sed, pero el mejor que podía pensar no está haciendo el truco:

sed -e '$s/\(.*\)\n$//' abc

Alguna idea de cómo hacer esto?

  • newline es solo un personaje para unix saltos de línea. DOS nuevas líneas son dos caracteres. Por supuesto, literal «\n» es de dos caracteres. Que estás buscando realmente?
  • Aunque la representación podría ser \n, en linux es uno de los personajes
  • ¿Puede explicar por qué quieres hacer esto? Los archivos de texto se suponía que debía terminar con un final de línea, a menos que estén completamente vacías. Me parece extraño que te gustaría tener un archivo truncado?
  • La razón habitual para hacer algo como esto es para eliminar un punto y coma final de la última línea de un archivo CSV. Sed funciona bien, pero los saltos de línea tienen que ser tratados de manera diferente.
  • Sí, este es para Linux, así que gracias por la corrección que el salto de línea es un solo personaje. Fijo en el post.
  • Por favor no borrar nunca el final de salto de línea en un archivo de salto de línea terminada en líneas. Se tornillos de todo tipo de cosas.
  • la informática, por cada buena razón por la que hay que hacer algo no existe una buena razón para no hacerlo, y viceversa.» -Jesús – «no deberías hacer eso» es un horrible respuesta no importa la pregunta. El formato correcto es: [forma de] pero [por qué puede ser mala idea]. #sacrilegio
  • Una de las razones para eliminar la final de salto de línea si usted es de tuberías de la cadena a otro lugar, y usted no puede tener un final de salto de línea.

22 Comentarios

  1. 206
    perl -pe 'chomp if eof' filename >filename2

    o, para editar el archivo en su lugar:

    perl -pi -e 'chomp if eof' filename

    [nota del Editor: -pi -e fue originalmente -pie, pero, como han señalado varios de los comentaristas y explicado por @hvd, éste no funciona.]

    Este fue descrito como un «perl blasfemia’ en el awk sitio web de vi.

    Pero, en una prueba, funcionó.

    • Sí, funciona.
    • Usted puede hacer que sea más seguro mediante el uso de chomp. Y es mejor que sorber el archivo.
    • La blasfemia a pesar de que es, funciona muy bien. perl -i-pe ‘chomp si ef’ nombre de archivo. Gracias.
    • La cosa divertida sobre la blasfemia y la herejía es generalmente odiado porque es correcto. 🙂
    • feliz blasfemia!
    • No es bonito, pero funciona. Renunciar a ella por el ejército suizo motosierra.
    • Pequeña corrección: puede utilizar perl -pi -e 'chomp if eof' filename, para editar un archivo en lugar de en lugar de crear un archivo temporal
    • perl -pie 'chomp if eof' filename -> no se Puede abrir el script de perl «chomp si ef»: No existe el fichero o el directorio; perl -pi -e 'chomp if eof' filename -> obras
    • ¿Por qué es -pie «blasfemia» y ¿por qué no se comportan de la misma como -pi -e? Alguien sabe?
    • Yo no sé acerca de la «blasfemia» de parte de otros que tal vez el mero hecho de recomendar perl podría ser considerado una blasfemia en un awk sitio web, pero la razón por la -pie y -pi -e no funcionan de la misma manera es que el -i opción toma un argumento opcional. -pie utiliza e como argumento para -i, especificando la copia de seguridad sufijo, y, a continuación, interpreta 'chomp if eof' como un nombre de archivo, ya que no es precedida por un -e opción. -pi -e omite el argumento para -i, y permite -e a ser tratada como una opción.
    • Esto elimina el caracter de cada línea en Mac OS X…
    • Esto también se convierte \r\n a \n
    • no todos los de Perl blasfemia? 😉

  2. 53

    Usted puede tomar ventaja del hecho de que shell comando sustituciones eliminando los caracteres de salto de línea:

    Formulario Simple que funciona en bash, ksh, zsh:

    printf %s "$(< in.txt)" > out.txt

    Portátil (POSIX) alternativa (un poco menos eficiente):

    printf %s "$(cat in.txt)" > out.txt

    Nota:

    • Si in.txt termina con múltiples caracteres de nueva línea, la sustitución de comandos elimina todos de ellos – gracias, @Sparhawk. (No quitar espacios en blanco caracteres que no sean tirados saltos de línea.)
    • Desde este enfoque lee todo el archivo de entrada en la memoria, es aconsejable sólo para archivos más pequeños.
    • printf %s asegura que no newline se anexa a la salida (es compatible con POSIX alternativa a la no estándar echo -n; ver http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html y https://unix.stackexchange.com/a/65819)

    Un guía para las otras respuestas:

    • Si Perl está disponible, vaya para el aceptado respuesta – es simple y eficaz memoria (no leer todo el archivo de entrada a la vez).

    • De lo contrario, considere la posibilidad de ghostdog74 del Awk respuesta – es claro, pero también la memoria-eficiente; un más legible equivalente (POSIX) es:

      • awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
      • Impresión se retrasa por una línea, de modo que el final de la línea puede ser manejado en el END bloque, donde se imprimen sin un final \n debido a la configuración de la salida-separador de registro (OFS) a una cadena vacía.
    • Si quieres un detallado, pero rápida y robusta solución que verdaderamente ediciones en el lugar (como contraposición a la creación de una temp. archivo que sustituye a la original), considere la posibilidad de jrockway del secuencia de comandos Perl.

    • N. B. si hay varios saltos de línea al final del archivo, este comando eliminar a todos ellos.
  3. 44

    Usted puede hacer esto con head de GNU coreutils, apoya a los argumentos relativos al final del archivo. Así que para dejar fuera el último byte de uso:

    head -c -1

    A prueba para un final de salto de línea se puede utilizar tail y wc. En el ejemplo siguiente se guarda el resultado en un archivo temporal y, posteriormente, se sobrescribe el original:

    if [[ $(tail -c1 file | wc -l) == 1 ]]; then
      head -c -1 file > file.tmp
      mv file.tmp file
    fi

    Usted podría también utilizar sponge de moreutils a hacer «en lugar de» edición:

    [[ $(tail -c1 file | wc -l) == 1 ]] && head -c -1 file | sponge file

    Usted también puede hacer un general de la función reutilizable por el relleno de este en su .bashrc de archivo:

    # Example:  remove-last-newline < multiline.txt
    function remove-last-newline(){
        local file=$(mktemp)
        cat > $file
        if [[ $(tail -c1 $file | wc -l) == 1 ]]; then
            head -c -1 $file > $file.tmp
            mv $file.tmp $file
        fi
        cat $file
    }

    Actualización

    Como señaló KarlWilbur en los comentarios y se utiliza en Sorentar s respuesta, truncate --size=-1 puede reemplazar head -c-1 y apoya la edición en el lugar.

    • Mejor solución de todas hasta el momento. Utiliza una herramienta estándar que realmente cada distribución de Linux tiene, y es concisa y clara, sin ningún tipo de sed o el perl de la hechicería.
    • Solución agradable. Uno de los cambios es que creo que yo uso truncate --size=-1 en lugar de head -c -1 ya que sólo cambia el tamaño del archivo de entrada en lugar de la lectura en el archivo de entrada, se escriben en otro archivo, a continuación, en sustitución de la original con el archivo de salida.
    • Buen punto, he añadido una nota al respecto
    • Tenga en cuenta que head -c -1 va a eliminar el último carácter, independientemente de si se trata de una nueva línea o no, es por eso que usted tiene que comprobar si el último carácter es un salto de línea antes de que usted la elimine.
  4. 16
    head -n -1 abc > newfile
    tail -n 1 abc | tr -d '\n' >> newfile

    Edit 2:

    Aquí es un awk versión (corregido) que no acumular una enorme matriz:

    awk ‘{if (línea) línea de impresión; línea=$0} END {printf $0}’ abc

    • Buenas original manera de pensar. Gracias Dennis.
    • el awk versión elimina las líneas en blanco así..
    • Estás en lo correcto. Remitir a su awk versión. Se necesita dos compensaciones (y una prueba diferente) y yo sólo uno. Sin embargo, puede utilizar printf en lugar de ORS.
    • usted puede hacer que la salida de un tubo con la sustitución de procesos: head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
    • Que no hace la misma cosa. Solo tuya da la última línea (sin salto de línea). El OP quiere que el todo archivo sólo con el último caracter eliminado. Su línea de trabajo sería como este: head -n -1 ifscomma && cat <(tail -n 1 ifscomma | tr -d '\n') o head -n -1 ifscomma | cat - <(tail -n 1 ifscomma | tr -d '\n'). En el último, el guión hace cat para concatenar lo que viene a través de la tubería con la salida del proceso de sustitución. De lo contrario, la salida de head sería ignorado.
    • tienes razón, se me olvidó el guión.
    • Se me olvidó editar el nombre del archivo en mi comentario anterior para cambiar el archivo de prueba que se utiliza para el nombre de la muestra «abc»: s/ifscomma/abc/g
    • Esto funcionó más rápido que el perl de comando en un archivo de 1MB para mí. Muchas gracias!
    • -C en lugar de n en la cabeza y en la cola debe ser aún más rápido.
    • Para mí, head-n -1 abc quitó la última línea real del archivo, dejando un final de salto de línea; la cabeza -c -1 abc parecía funcionar mejor
    • sólo otra variante del «uno forro» con cat ejemplos se muestran en los comentarios (no de la tubería es necesario, utilizando sólo la sustitución de procesos, siéntase libre de cambiar el head o tail opciones como sea necesario): cat <(head -n -1 abc) <(tail -n 1 abc | tr -d '\n')

  5. 10

    gawk

       awk '{q=p;p=$0}NR>1{print q}END{ORS = ""; print p}' file
    • Todavía se ve como un montón de personajes para mí… aprendiendo poco a poco :). Hace el trabajo sin embargo. Gracias ghostdog.
    • awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file esto debería ser más fácil de leer.
    • Cómo acerca de: awk 'NR>1 {print p} {p=$0} END {printf $0}' file.
  6. 8

    Si quieres hacerlo bien, necesitas algo como esto:

    use autodie qw(open sysseek sysread truncate);
    
    my $file = shift;
    open my $fh, '+>>', $file;
    my $pos = tell $fh;
    sysseek $fh, $pos - 1, 0;
    sysread $fh, my $buf, 1 or die 'No data to read?';
    
    if($buf eq "\n"){
        truncate $fh, $pos - 1;
    }

    Abrimos el fichero para lectura y anexando; la apertura para anexar significa que ya estamos seeked al final del archivo. A continuación, obtener la posición numérica del final del archivo con tell. Podemos usar ese número para buscar un carácter y, a continuación, leemos que uno de los personajes. Si es un salto de línea, se trunca el archivo para el personaje antes de que el salto de línea, de lo contrario, no hacemos nada.

    Este se ejecuta en la constante de tiempo y de espacio continuo, para cualquier entrada, y no requiere más espacio en disco, ya sea.

    • pero que tiene la desventaja de no restablecer la propiedad/los permisos para el archivo…eh, espera…
    • Detallado, pero a la vez rápido y robusto – parece ser la única true en el lugar de edición de archivos respuesta aquí (y ya que no puede ser obvio para todos: este es un Perl secuencia de comandos).
  7. 8

    Un método muy simple para una sola línea de archivos, que requieren de GNU echo de coreutils:

    /bin/echo -n $(cat $file)
    • Esta es una manera decente, si no es demasiado caro (repetitivo).
    • Creo que esta solución se merece más votos.
    • Este tiene problemas cuando \n está presente. Como se convierte a una nueva línea.
    • También parece que funciona para archivos multi-línea es la $(...) es citado
    • definitivamente necesidad de citar que… /bin/echo -n "$(cat infile)" También, no estoy seguro de cuál es el máximo len de echo o el shell sería a través de os/shell versiones/distros (yo estaba solo googlear este & era un agujero de conejo), así que no estoy seguro de cómo portátil (o rendimiento) que en realidad sería otra cosa que archivos pequeños, pero para archivos pequeños, grandes.
  8. 5

    Aquí es un agradable, ordenado solución Python. No he hecho el intento de ser conciso aquí.

    Esto modifica el archivo en el lugar, en lugar de hacer una copia del archivo y desmontaje de la nueva línea de la última línea de la copia. Si el archivo es grande, este será mucho más rápido que el Perl de la solución que se ha elegido como la mejor respuesta.

    Se trunca un archivo por dos bytes si los dos últimos bytes son CR/LF, o por un byte si el último byte LF. No intente modificar el archivo si el último byte(s) no (CR)LF. Se encarga de los errores. Probado en Python 2.6.

    Poner esto en un archivo llamado «striplast» y chmod +x striplast.

    #!/usr/bin/python
    
    # strip newline from last line of a file
    
    
    import sys
    
    def trunc(filename, new_len):
        try:
            # open with mode "append" so we have permission to modify
            # cannot open with mode "write" because that clobbers the file!
            f = open(filename, "ab")
            f.truncate(new_len)
            f.close()
        except IOError:
            print "cannot write to file:", filename
            sys.exit(2)
    
    # get input argument
    if len(sys.argv) == 2:
        filename = sys.argv[1]
    else:
        filename = "--help"  # wrong number of arguments so print help
    
    if filename == "--help" or filename == "-h" or filename == "/?":
        print "Usage: %s <filename>" % sys.argv[0]
        print "Strips a newline off the last line of a file."
        sys.exit(1)
    
    
    try:
        # must have mode "b" (binary) to allow f.seek() with negative offset
        f = open(filename, "rb")
    except IOError:
        print "file does not exist:", filename
        sys.exit(2)
    
    
    SEEK_EOF = 2
    f.seek(-2, SEEK_EOF)  # seek to two bytes before end of file
    
    end_pos = f.tell()
    
    line = f.read()
    f.close()
    
    if line.endswith("\r\n"):
        trunc(filename, end_pos)
    elif line.endswith("\n"):
        trunc(filename, end_pos + 1)

    P. S. En el espíritu de «Perl de golf», aquí está mi menor Python solución. Se sorbe todo el archivo de entrada estándar en la memoria, tiras de todos los saltos de línea fuera de la final, y escribe el resultado en la salida estándar. No tan lacónico como el Perl; usted simplemente no puede vencer Perl para poco complicado rápido cosas como esta.

    Quitar el «\n» desde la convocatoria de .rstrip() y se tira todo el espacio en blanco desde el final del archivo, incluyendo múltiples líneas en blanco.

    Poner esto en «slurp_and_chomp.py» y, a continuación, ejecute python slurp_and_chomp.py < inputfile > outputfile.

    import sys
    
    sys.stdout.write(sys.stdin.read().rstrip("\n"))
    • os.ruta de acceso.isfile() le dirá acerca del archivo presencia. El uso de try/except puede capturar una gran cantidad de errores diferentes 🙂
  9. 3
    $ perl -e 'local $/; $_ = <>; s/\n$//; print' a-text-file.txt 
    

    Ver también Coincide con cualquier carácter (incluyendo saltos de línea) en el sed.

    • Que se lleva a cabo todos los saltos de línea. Equivalente a tr -d '\n'
    • Williamson: señalar y corregir.
    • Esto funciona bien también, probablemente, menos blasfemo que paviums del.
    • Sinan, aunque Linux y Unix podría definir archivos de texto, para terminar con un salto de línea, Windows no plantea tal requisito. El bloc de notas, por ejemplo, se escribe sólo los caracteres que escriba sin añadir nada extra al final. Compiladores de C pueden requerir un archivo de código fuente final con un salto de línea, pero los archivos fuente de C no son «sólo» archivos de texto, por lo que puede tener requisitos adicionales.
    • en ese sentido, la mayoría de javascript/css minifiers va eliminando los saltos de línea, y, sin embargo, producir archivos de texto.
    • Kennedy y @ysth: Hay un argumento interesante que hay de por qué estos archivos no son realmente los archivos de texto y tal.

  10. 3

    Una solución rápida es utilizando la utilidad gnu truncate:

    [ -z $(tail -c1 file) ] && truncate -s-1

    La prueba será verdadero si el archivo no tiene un punto final de la línea nueva.

    La eliminación es muy rápido, realmente en el lugar, no es nuevo archivo que se necesita y la búsqueda es también la lectura de el final de un byte (cola -c1).

    • alguna manera de conseguir que esto funcione con stdin?
    • truncar: falta el archivo operando
    • es sólo falta de la parte final del nombre de archivo en el ejemplo, es decir, [ -z $(tail -c1 filename) ] && truncate -s -1 filename (también, en respuesta a otro comentario, el truncate comando no funciona con stdin, el nombre de un archivo es necesario)
  11. 2

    Usando dd:

    file='/path/to/file'
    [[ "$(tail -c 1 "${file}" | tr -dc '\n' | wc -c)" -eq 1 ]] && \
        printf "" | dd  of="${file}" seek=$(($(stat -f "%z" "${file}") - 1)) bs=1 count=1
        #printf "" | dd  of="${file}" seek=$(($(wc -c < "${file}") - 1)) bs=1 count=1
  12. 2
    perl -pi -e 's/\n$//if(eof)' your_file
    • Efectivamente el mismo que el aceptado la respuesta, pero posiblemente más clara en el concepto de los no-usuarios de Perl. Tenga en cuenta que no hay necesidad para el g o los paréntesis alrededor de eof: perl -pi -e 's/\n$// if eof' your_file.
  13. 2

    Suponiendo Unix tipo de archivo y desea que sólo el último salto de línea funciona esto.

    sed -e '${/^$/d}'

    No va a funcionar en múltiples saltos de línea…

    * Sólo funciona si la última línea es una línea en blanco.

    • Esto sólo funciona si la última línea está en blanco.
    • He aquí un sed solución que funciona incluso para un no blanco en la última línea: stackoverflow.com/a/52047796
  14. 1

    Otra respuesta FTR (y mi favorito!): eco/gato de la cosa que usted desea tira y capturar la salida a través de comillas simples inclinadas. La final de salto de línea será despojado. Por ejemplo:

    # Sadly, outputs newline, and we have to feed the newline to sed to be portable
    echo thingy | sed -e 's/thing/sill/'
    
    # No newline! Happy.
    out=`echo thingy | sed -e 's/thing/sill/'`
    printf %s "$out"
    
    # Similarly for files:
    file=`cat file_ending_in_newline`
    printf %s "$file" > file_no_newline
    • He encontrado el gato-printf combo por casualidad (estaba tratando de conseguir que el comportamiento opuesto). Tenga en cuenta que esto le quite TODO tirados, saltos de línea, no sólo de la última.
  15. 1

    POSIX SED:

    ‘${/^$/d}’

    $ - match last line
    
    
    { COMMANDS } - A group of commands may be enclosed between { and } characters. This is particularly useful when you want a group of commands to be triggered by a single address (or address-range) match.
    • Creo que esto sólo va a eliminar si la última línea está en blanco. No le van a quitar la final de salto de línea si la última línea no está en blanco. Por ejemplo, echo -en 'a\nb\n' | sed '${/^$/d}' no quitar nada. echo -en 'a\nb\n\n' | sed '${/^$/d}' va a quitar ya que toda la última línea está en blanco.
  16. 0

    La única vez que he querido hacer esto es el código de golf, y luego he copiado el código en el archivo y pegado en un echo -n 'content'>file declaración.

    • Hey ahora… funciona.
    • A mitad de camino; enfoque completo aquí.
  17. 0

    He tenido un problema similar, pero estaba trabajando con un archivo de windows y la necesidad de mantener los CRLF — mi solución en linux:

    sed 's/\r//g' orig | awk '{if (NR>1) printf("\r\n"); printf("%s",$0)}' > tweaked
  18. 0
    sed -n "1 x;1 !H
    $ {x;s/\n*$//p;}
    " YourFile

    Debe eliminar cualquier última ocurrencia de \n en el archivo. No funciona en un archivo grande (debido a la sed limitación de búfer)

  19. 0

    ruby:

    ruby -ne 'print $stdin.eof ? $_.strip : $_'

    o:

    ruby -ane 'q=p;p=$_;puts q if $.>1;END{print p.strip!}'
  20. 0

    Esta es una buena solución si usted necesita para trabajar con tubos/redirección en lugar de la lectura/salida o a un archivo. Esto funciona con una o varias líneas. Funciona si hay un final de salto de línea o no.

    # with trailing newline
    echo -en 'foo\nbar\n' | sed '$s/$//' | head -c -1
    
    # still works without trailing newline
    echo -en 'foo\nbar' | sed '$s/$//' | head -c -1
    
    # read from a file
    sed '$s/$//' myfile.txt | head -c -1

    Detalles:

    • head -c -1 trunca el último carácter de la cadena, independientemente de lo que el personaje es. Así que si la cadena no termina con un salto de línea, entonces usted podría estar perdiendo un personaje.
    • Para resolver ese problema, se añade otro comando que se va a agregar un punto de salto de línea si no hay uno: sed '$s/$//' . La primera $ significa sólo aplicar el comando a la última línea. s/$// significa sustituir el «final de la línea» con «nada», que es básicamente no hacer nada. Pero tiene un lado el efecto de la adición de un final de salto de línea es que no hay uno.

    Nota: Mac por defecto de head no admite la -c opción. Usted puede hacer brew install coreutils y uso ghead lugar.

Dejar respuesta

Please enter your comment!
Please enter your name here