Desde finales de enero estoy publicando un tweetcode al día en gnusocial (@oneliners), y en twitter (@twtcodes). El concepto viene de una idea que tuvo @hacklego para hackliza: un twitcode sería un pequeño codigo, de no más de 140 caracteres, que tenga alguna utilidad. Parte de la idea, era también dar una explicación de como funciona, así que ahora que va más de un mes de estos twitcodes, toca empezar a explicarlos. Veamos...

1. Colorear 0s y 1s

1
sed 's/1/\x1b\[1;32m1/g'|sed 's/0/\x1b\[1;31m0/g'|sed 's/\x1b\[1;3[12]m[01]/&\x1b\[0m/g'


En gnusocial, twitter.

Desglose:

1
2
3
sed 's/1/\x1b\[1;32m1/g' | # Colorea los 1s de verde
sed 's/0/\x1b\[1;31m0/g' | # Colorea los 0s de rojo
sed 's/\x1b\[1;3[12]m[01]/&\x1b\[0m/g' # A los 0 o 1 coloreados les añade un "fin de color"

Ojo con el orden! la primera regexp no crea ningún 0 que la segunda pueda pisar.

2. Ordenar filas y mostrar el total

1
sort -rn|awk '{ c+=1;t+=$1; print } END { print "\nTotal of " c " = " t }'


En gnusocial, twitter.

Desglose:

1
2
3
4
sort -rn  | # Ordena los resultados numéricos de forma descendente
awk '{ c+=1;t+=$1; print }
      END
     { print "\nTotal of " c " = " t }'

El truco, claro, está en el awk

1
2
3
4
5
6
7
8
# Por cada fila
{
  c+=1;  # Incrementa un contador de líneas
  t+=$1; # Suma el valor de la primera fila al total
  print  # Imprime la línea
}
 END     # Después de haber procesado todas las líneas
{ print "\nTotal of " c " = " t } # Muestra el número de líneas y la suma total

3. Mostrar el espacio que ocupa cada directorio, gráficamente

1
du -d0 * 2>/dev/null|gnuplot -p -e 'set xtics nomirror ro by -45; plot "/dev/stdin" u 1:xticlabels(2) w boxes ti ""'


En gnusocial, twitter.

Desglose:

1
2
du -d0 * 2>/dev/null | # Extrae el peso de cada directorio a partir del actual
gnuplot -p -e 'set xtics nomirror ro by -45; plot "/dev/stdin" u 1:xticlabels(2) w boxes ti ""'

El script de gnuplot para generar la gráfica hace así:

1
2
3
4
5
set xtics nomirror ro by -45 # Inclina las etiquetas del eje X (los directorios)
# (plot "/dev/stdin") Get the data from stdin
# (u 1:xticlabels(2)) Use first column as the value and the second as the labels in X axis
# (w boxes)           Plot the data as a barchart
# (ti "")             Set an empty title

4. Mostrar las IPs de un log

Apache:

1
sudo sh -c 'for i in /var/log/apache2/acc*;do if echo $i|grep -q gz$;then zcat $i;else cat $i;fi;done'|cut -d\  -f1|sort|uniq -c|sort -rn

Nginx:

1
sudo sh -c 'for i in /var/log/nginx/acc*;do if echo $i|grep -q gz$;then zcat $i;else cat $i;fi;done'|cut -d\  -f1|sort|uniq -c|sort -rn


En gnusocial, twitter.

Desglose:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
sudo sh -c # Pide permisos de root
    for i in /var/log/apache2/acc*;do  # Itera sobre los logs de acceso

        # Usa `zcat` con los archivos comprimidos
        if echo $i|grep -q gz$;then
            zcat $i

        # y solo `cat` para archivos en texto plano
        else
            cat $i
        fi
    done |
cut -d\  -f1 | # Corta la primera columna (la IP)
sort         | # Ordena las entradas
uniq -c      | # Cuenta las entradas únicas
sort -rn       # Ordena los resultados desendentemente

5. Sniffar a que host se connecta un cliente SSL

1
f='ssl.handshake.extensions_server_name'; tshark -Y $f -Tfields -e $f


En gnusocial, twitter.

Desglose:

1
2
3
f='ssl.handshake.extensions_server_name' # El campo con la información
# Elimina los paquetes que no contienen el campo y lo imprimen
tshark -Y $f -Tfields -e $f

6. Encontrar los paquetes necesarios para ejecutar un binario

1
deps() { for i in `ldd "$1"|awk '{print $1}'`;do apt-file -l search "$i" | head -1;done | sort | uniq; }


En gnusocial, twitter.

Desglose:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
deps() {
    for i in `ldd "$1" |       # Itera sobre la lista de dependencias de librerías compartidas
              awk '{print $1}' # se queda con el nombre del archivo
              `;do

              apt-file -l search "$i" | # Busca el archivo por nombre en APT-file
              head -1;                  # mantiene el primer resultado
    done |
    sort | # Ordena los resultados
    uniq;  # filtra los repetidos
}

7. Descargar metadatos de un stream de radio

1
r=get(argv[1],headers={'Icy-MetaData':1},stream=True);m=int(r.headers['icy-metaint']);r.raw.read(m);print r.raw.read(ord(r.raw.read(1))*16)


En gnusocial, twitter.

Desglose:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/usr/bin/env python
from sys import *
from requests import *

r = get(argv[1], headers={'Icy-MetaData':1}, stream=True) # Pide el stream, con los metadatos

m = int(r.headers['icy-metaint'])        # icy-metaint indica cada cuantos elementos hay metadatos
r.raw.read(m)                            # Se salta los `m` primeros bytes de no-metadatos
metalength = ord(r.raw.read(1))*16       # El primer byte indica la longitud, dividida entre 16
print r.raw.read(metalength)             # Lee los metadatas, con la longitud indicada

Referencia: SmackFu: Shoutcast Metadata Protocol

8. Extraer el nombre de un volumen FAT

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def get(f):
  # El byte 38 indica el tipo de partición FAT, 0x28 o 0x29 para FAT12 y FAT16
  f.seek(38)
  sig = f.read(1)

  if sig in '()': i = 43 # En FAT12/16, la etiqueta está en el offset 43
  else: i = 71           # En FAT32, en el 71

  f.seek(i)
  return f.read(11).strip() # Lee 11 bytes a partir del offset


En gnusocial, twitter.

Referencia: FAT - OSDev Wiki

9. Bencodear un objeto python

1
j=''.join;e=lambda x:eval({46:"'d%se'%j([e(k)+e(x[k])for k in x])",45:"'l%se'%j(map(e,x))",64:"'i%se'%x",71:"'%s:'%len(x)+x"}[len(dir(x))])


En gnusocial, twitter.

Desglose:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
j=''.join
e=lambda x:eval( # Por cada elemento
    {46: # Si es un diccionario (len(dir(dict)) == 46)
         "'d%se'%j([e(k)+e(x[k])for k in x])", # Concatena "d", el bencode de claves, el de los valores y "e"
     45: # Si es una lista (len(dir(list)) == 45)
         "'l%se'%j(map(e,x))", # Concatena "l", el bencode de cada elemento y "e"
     64: # Si es un entero (len(dir(list)) == 64)
         "'i%se'%x",  # Concatena "i", el número y "e"
     71: # Si es un string (len(dir(list)) == 71)
         "'%s:'%len(x)+x" # Concatena la lontigud de la cadena, ":" y la cadena

    }[len(dir(x))]) # Los tipos se distinguen por el número de métodos a los que dan acceso (depende de la versión de python)

Lo de utilizar el número de métodos es bastante sucio, pero sin eso resultaba imposible bajar de los 141, la otra versión era esta:

1
j=''.join;e=lambda x:eval({dict:"'d%se'%j([e(k)+e(x[k])for k in x])",list:"'l%se'%j(map(e,x))",int:"'i%se'%x",str:"'%s:'%len(x)+x"}[type(x)])

Desglosado, lo unico que cambia es la forma de acceder a diccionario de strings a evaluar...

1
2
3
4
5
6
7
j=''.join
e=lambda x:eval({
    dict:"'d%se'%j([e(k)+e(x[k])for k in x])",
    list:"'l%se'%j(map(e,x))",
    int:"'i%se'%x",
    str:"'%s:'%len(x)+x"
}[type(x)])

10. Mostrar un JSON de forma amigable

1
python -m json.tool


En gnusocial, twitter.

Que simplemente funciona :p