es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Contar las nuevas líneas finales utilizando utilidades POSIX, GNU coreutils o Perl.

Estoy buscando formas de contar el número de saltos de línea al final de los datos, que pueden ser binarios, ya sea:
– leídos desde la entrada estándar
– o ya en una variable de shell (entonces, por supuesto, “binario” excluye al menos 0x0)
usando utilidades POSIX o coreutils o tal vez Perl.

Esto debería funcionar sin archivos temporales o FIFOs.

Cuando la entrada está en una variable de shell, ya tengo la siguiente solución (posiblemente fea pero) funcionando:

original_string=$'abc\n\n\def\n\n\n'
string_without_trailing_newlines="$( printf '%s' "${original_string}" )"
printf '%s' $(( ${#original_string}-${#string_without_trailing_newlines} ))

que devuelve 3 en el ejemplo anterior.

La idea anterior es simplemente restar las longitudes de las cadenas y usar la “característica” de la sustitución de comandos que descarta cualquier salto de línea final.

Casos de prueba:

printf ''             |  función   resulta en: 0
printf '\n'           |  función   resulta en: 1
printf '\n\n'         |  función   resulta en: 2
printf '\n\n\n'       |  función   resulta en: 3
printf 'a'            |  función   resulta en: 0
printf 'a\n'          |  función   resulta en: 1
printf 'a\n\n'        |  función   resulta en: 2
printf '\na\n\n'      |  función   resulta en: 2
printf 'a\n\nb\n'     |  función   resulta en: 1

Para los casos especiales en los que NUL forma parte de la cadena (lo cual de todas formas solo funciona al leer desde la entrada estándar, no al proporcionar la cadena en la variable de la shell), los resultados son indefinidos pero generalmente deberían ser cualquiera de los siguientes:

printf '\n\x00\n\n'   |  función   resulta en: 1
printf 'a\n\n\x00\n'  |  función   resulta en: 2

que cuenta los saltos de línea hasta el NUL

o:

printf '\n\x00\n\n'   |  función   resulta en: 2
printf 'a\n\n\x00\n'  |  función   resulta en: 1

que cuenta los saltos de línea después del NUL

o:

printf '\n\x00\n\n'   |  función   resulta en: 3
printf 'a\n\n\x00\n'  |  función   resulta en: 3

que ignora cualquier NUL “trailing”, siempre y cuando estén justo antes, dentro o justo después de los NUL finales

o:
dando error

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución en shell que funciona tanto para leer desde la entrada estándar como desde una variable de shell es:

    #!/bin/sh
    
    if [ -t 0 ]; then                   # leer desde una variable
      original_string='abc\n\n\def\n\n\n'
      string_without_trailing_newlines=$(printf '%s' "$original_string")
    else                                # leer desde stdin
      string_without_trailing_newlines=$(cat -)
    fi
    
    # eliminar nulos finales (si están presentes)
    string_without_trailing_nuls=${string_without_trailing_newlines%$'\0'*}
    
    # contar saltos de línea finales (incluyendo nulos)
    trailing_newlines=$(printf '%s' "$string_without_trailing_newlines" | tail -c "+$((${#string_without_trailing_nuls}+1))" | tr -cd '\n' | wc -c)
    
    echo "$trailing_newlines"
    

    Explicación:

    • El script verifica primero si la entrada estándar está vacía y lee desde una variable de shell si este es el caso.
    • La variable de cadena se pasa a través de printf para convertirla en una cadena terminada en nulo, que es requerida por algunos de los comandos posteriores (por ejemplo, tail no funciona de otra manera).
    • La variable string_without_trailing_nuls se crea eliminando cualquier nulo final (si está presente) de la cadena, utilizando el operador % con un patrón de comodín.
    • La variable trailing_newlines se crea contando los saltos de línea (incluyendo nulos) al final de la cadena utilizando los comandos tail, tr y wc.

    Esta solución debería funcionar correctamente para cualquier combinación de caracteres imprimibles y no imprimibles, incluyendo nulos, y debería ser compatible con POSIX.

    Tenga en cuenta que las pruebas de casos proporcionadas en la indicación no son una sintaxis válida de shell, ya que el comando printf requiere una cadena de formato (por ejemplo, printf '%s\n' '' en lugar de printf ''), y las comillas invertidas en lugar del símbolo acento grave para invocar la sustitución de comandos (por ejemplo, echo `command` en lugar de echo `command`).

Comments are closed.