Tengo un archivo CSV que se ve así
AS2345, ASDF1232, Mr. Plain Example, 110 Binary ave., Atlantis, RI, 12345, (999) 123-5555,1.56 AS2345, ASDF1232, Sra. Plain Example, 1121110 Ternary st. 110 Binary ave .., Atlantis, RI, 12345, (999) 123-5555,1.56 AS2345, ASDF1232, Mr. Plain Example, 110 Binary ave., Liberty City, RI, 12345, (999) 123-5555,1.56 AS2345, ASDF1232, Mr. Plain Example, 110 Ternary ave., Some City, RI, 12345, (999) 123-5555,1.56
Necesito ordenarlo por longitud de línea incluyendo espacios. El siguiente comando no incluye espacios, ¿hay alguna forma de modificarlo para que funcione para mí?
cat $@ | awk '{ print length, $0 }' | sort -n | awk '{$1=""; print $0}'
Respuestas:
Responder
O, para hacer su subclasificación original (quizás no intencional) de cualquier línea de igual longitud:
En ambos casos, hemos resuelto su problema declarado alejándonos de awk para su corte final.
Líneas de longitud coincidente: qué hacer en caso de empate:
La pregunta no especificaba si se deseaba una clasificación adicional para líneas de longitud coincidente. Supuse que esto no es deseado y sugerí el uso de
-s
(--stable
) para evitar que tales líneas se ordenen entre sí y mantenerlas en el orden relativo en el que ocurren en la entrada.(Aquellos que quieran tener más control sobre la clasificación de estos lazos podrían considerar la
--key
opción de clasificación ).Por qué falla la solución intentada de la pregunta (reconstrucción de línea awk):
Es interesante notar la diferencia entre:
Ceden respectivamente
La sección relevante del manual de (gawk) solo menciona como un aparte que awk reconstruirá la totalidad de $ 0 (basado en el separador, etc.) cuando cambie un campo. Supongo que no es un comportamiento loco. Tiene esto:
"Finalmente, hay momentos en los que es conveniente forzar a awk a reconstruir todo el registro, usando el valor actual de los campos y OFS. Para hacer esto, use la asignación aparentemente inocuo:"
"Esto obliga a awk a reconstruir el registro".
Entrada de prueba que incluye algunas líneas de igual longitud:
fuente
cat $@
está roto. Definitivamente quieres citarlo, comocat "$@"
La solución AWK de neillb es excelente si realmente quieres usarla
awk
y explica por qué es una molestia allí, pero si lo que quieres es hacer el trabajo rápidamente y no importa lo que hagas, una solución es usar Lasort()
función de Perl con una rutina de capa personalizada para iterar sobre las líneas de entrada. Aquí hay una línea:Puede poner esto en su tubería donde lo necesite, ya sea recibiendo STDIN (desde
cat
o una redirección de shell) o simplemente dando el nombre de archivo a Perl como otro argumento y deje que abra el archivo.En mi caso, primero necesitaba las líneas más largas, así que cambié
$a
y$b
en la comparación.fuente
cat testfile.txt | perl -e 'print sort { length($a) <=> length($b) } <>' > out.txt
type testfile.txt | perl -e "print sort { length($a) <=> length($b) } <>" > out.txt
Pruebe este comando en su lugar:
fuente
Resultados de referencia
A continuación, se muestran los resultados de un punto de referencia entre soluciones de otras respuestas a esta pregunta.
Método de prueba
Resultados
perl
solución de Caleb tomó 11.2 segundos.perl
solución tardó 11,6 segundosawk
solución n . ° 1 de neillb tardó 20 segundosawk
solución de neillb # 2 tomó 23 segundosawk
solución de Anubhava tomó 24 segundosawk
solución de Jonathan tomó 25 segundosbash
solución de Fretz tarda 400 veces más que lasawk
soluciones (usando un caso de prueba truncado de 100000 líneas). Funciona bien, solo lleva una eternidad.perl
Opción extraAdemás, he agregado otra solución Perl:
fuente
Golpe puro:
fuente
La
length()
función incluye espacios. Haría ajustes menores en su canalización (incluso evitar UUOC ).El
sed
comando elimina directamente los dígitos y los dos puntos agregados por elawk
comando. Alternativamente, manteniendo su formato desdeawk
:fuente
Encontré que estas soluciones no funcionarán si su archivo contiene líneas que comienzan con un número, ya que se ordenarán numéricamente junto con todas las líneas contadas. La solución es dar
sort
el-g
indicador (general-numeric-sort) en lugar de-n
(numeric-sort):fuente
-n
a los sugeridos-g
para producir ninguna mejora, por lo que espero que no. Ya he abordado, en mi respuesta, cómo prohibir la subclasificación de líneas de igual longitud (usando--stable
). Si eso fue lo que quisiste decir, ¡gracias por llamar mi atención! También he agregado una entrada considerada para probar.awk
parte generará una lista de líneas con el prefijo de longitud de línea y un espacio. Instalarlosort -n
funcionará como se espera. Pero si alguna de esas líneas ya tiene un número al principio, esas líneas comenzarán con longitud + espacio + número.sort -n
no tiene en cuenta ese espacio y lo tratará como un número concatenado de longitud + número. El uso de la-g
bandera se detendrá en el primer espacio, produciendo una clasificación correcta. Pruébelo usted mismo creando un archivo con algunas líneas con prefijos numéricos y ejecute el comando paso a paso.sort -n
ignora el espacio y produce una clasificación incorrecta.sort -g
da salida al orden correcto.-n
insort (GNU coreutils) 8.21
. Lainfo
documentación se describe-g
como menos eficiente y potencialmente menos precisa (convierte números a flotantes), por lo que probablemente no la use si no es necesario.-n
: "Ordenar numéricamente. El número comienza cada línea y consta de espacios en blanco opcionales, un signo '-' opcional y cero o más dígitos posiblemente separados por miles de separadores, seguidos opcionalmente por un carácter de punto decimal y cero o más dígitos . Un número vacío se trata como '0'. La configuración regional 'LC_NUMERIC' especifica el carácter de punto decimal y el separador de miles. De forma predeterminada, un espacio en blanco es un espacio o una pestaña, pero la configuración regional 'LC_CTYPE' puede cambiar esto ".Con POSIX Awk:
Ejemplo
fuente
1) solución pura de awk. Supongamos que la longitud de la línea no puede ser más de 1024
nombre de archivo del gato | awk 'BEGIN {min = 1024; s = "";} {l = longitud ($ 0); si (l <min) {min = l; s = $ 0;}} END {print s} '
2) una solución bash de línea, suponiendo que todas las líneas tengan solo 1 palabra, pero puede modificarse para cualquier caso en el que todas las líneas tengan el mismo número de palabras:
LÍNEAS = $ (nombre de archivo del gato); para k en $ LINES; hacer printf "$ k"; echo $ k | wc -L; hecho | ordenar -k2 | cabeza -n 1 | cortar -d "" -f1
fuente
Aquí hay un método compatible con multibyte para clasificar líneas por longitud. Requiere:
wc -m
está disponible para usted (macOS lo tiene).LC_ALL=UTF-8
. Puede configurar esto en su .bash_profile, o simplemente colocándolo antes del siguiente comando.testfile
tiene una codificación de caracteres que coincide con su entorno local (por ejemplo, UTF-8).Aquí está el comando completo:
Explicando parte por parte:
l=$0; gsub(/\047/, "\047\"\047\"\047", l);
← hace una copia de cada línea en una variable awkl
y escapa doble'
para que la línea pueda repetirse de forma segura como un comando de shell (\047
es una comilla simple en notación octal).cmd=sprintf("echo \047%s\047 | wc -m", l);
← este es el comando que ejecutaremos, que hace eco de la línea escapadawc -m
.cmd | getline c;
← ejecuta el comando y copia el valor de recuento de caracteres que se devuelve a la variable awkc
.close(cmd);
← cierre la tubería al comando de shell para evitar alcanzar un límite del sistema en la cantidad de archivos abiertos en un proceso.sub(/ */, "", c);
← recorta el espacio en blanco del valor de recuento de caracteres que devuelvewc
.{ print c, $0 }
← imprime el valor de recuento de caracteres de la línea, un espacio y la línea original.| sort -ns
← ordena las líneas (por valores de recuento de caracteres antepuestos) numéricamente (-n
) y mantiene un orden de clasificación estable (-s
).| cut -d" " -f2-
← elimina los valores de recuento de caracteres antepuestos.Es lento (solo 160 líneas por segundo en un Macbook Pro rápido) porque debe ejecutar un subcomando para cada línea.
Alternativamente, solo haga esto únicamente con
gawk
(a partir de la versión 3.1.5, gawk es multibyte), que sería significativamente más rápido. Es un gran problema hacer todo el escape y las comillas dobles para pasar las líneas de forma segura a través de un comando de shell desde awk, pero este es el único método que pude encontrar que no requiere la instalación de software adicional (gawk no está disponible de forma predeterminada en Mac OS).fuente