A veces puede ser necesario mezclar aleatoriamente las líneas de un archivo o, inversamente, ordenar alfabéticamente (o numéricamente) las líneas en la salida de un comando. Veamos algunos ejemplos y usos prácticos de las herramientas shuf
y sort
en sistemas GNU/Linux.
Tanto shuf
como sort
son parte del paquete coreutils. Infinidad de veces demostré en este blog cómo utilizar sort
en conjunto con uniq
, por ejemplo al listar todos los dominios que están haciendo hotlink de nuestras imágenes. Este es un uso bastante básico de la herramienta sort
, y tal vez el más conocido. Sin embargo tiene usos más avanzados, al mismo tiempo que existe su contraparte shuf
, que se emplea para desordenar o mezclar las líneas en una salida o archivo pasado como parámetro.
Mezclar
shuf
permite generar (por salida estándar) permutaciones aleatorias en las líneas de un archivo o entrada estándar, lo que se conoce coloquialmente como mezclar o desordenar. Veamos un ejemplo partiendo de un archivo cuyas líneas se encuentran ordenadas alfabéticamente:
emi@hal9000:~$ grep multipart /etc/mime.types multipart/alternative multipart/appledouble multipart/byteranges multipart/digest multipart/encrypted multipart/form-data multipart/header-set multipart/mixed multipart/parallel multipart/related multipart/report multipart/signed multipart/voice-message
Al pasar la salida anterior a shuf
, se observa que se intercambian aleatoriamente:
emi@hal9000:~$ grep multipart /etc/mime.types | shuf multipart/appledouble multipart/related multipart/mixed multipart/parallel multipart/voice-message multipart/digest multipart/alternative multipart/signed multipart/report multipart/form-data multipart/header-set multipart/encrypted multipart/byteranges
Una opción interesante, que puede ser de utilidad al momento de desarrollar scripts, es -e
. Esta permite interpretar cada parámetro en la línea de comandos como si fuese una línea. Por ejemplo:
root@hal9000:~# shuf -e 1 2 3 4 5 4 5 2 3 1
root@hal9000:~# shuf -e 1 2 3 4 5 1 4 5 3 2
root@hal9000:~# shuf -e 1 2 3 4 5 1 4 2 3 5
Ordenar
Si lo que se necesita es aplicar algún tipo de ordenamiento sobre las líneas de un archivo, se debe recurrir a sort
. Esta permite ordenar según diferentes criterios, no sólo alfabéticamente.
root@hal9000:~# echo -e "Homero\nLisa\nBart\nMarge\nMaggie" Homero Lisa Bart Marge Maggie
Por defecto, sort
ordena las líneas alfabéticamente:
root@hal9000:~# echo -e "Homero\nLisa\nBart\nMarge\nMaggie" | sort Bart Homero Lisa Maggie Marge
Para ordenar inversamente (de la Z a la A) se debe agregar la opción -r
:
emi@hal9000:~$ echo -e "Homero\nLisa\nBart\nMarge\nMaggie" | sort -r Marge Maggie Lisa Homero Bart
Con esta herramienta es posible ordenar cualquier salida para ser procesada desde scripts, por ejemplo ordenar los sistemas de archivo montados según el tipo de dispositivo:
emi@hal9000:~$ mount sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) udev on /dev type devtmpfs (rw,nosuid,relatime,size=3999244k,nr_inodes=999811,mode=755) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=802812k,mode=755) /dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro) tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k) pstore on /sys/fs/pstore type pstore (rw,relatime) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=3168040k) /dev/sda4 on /data type ext4 (rw,relatime) /dev/sda3 on /home type ext4 (rw,relatime) tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,mode=755) cgroup on /sys/fs/cgroup/elogind type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/elogind/elogind-cgroups-agent,name=elogind) tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=802808k,mode=700,uid=1000,gid=1000) none on /run/user/1000 type tmpfs (rw,relatime,mode=700,uid=1000)
emi@hal9000:~$ mount | sort cgroup on /sys/fs/cgroup/elogind type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/elogind/elogind-cgroups-agent,name=elogind) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) /dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro) /dev/sda3 on /home type ext4 (rw,relatime) /dev/sda4 on /data type ext4 (rw,relatime) none on /run/user/1000 type tmpfs (rw,relatime,mode=700,uid=1000) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) pstore on /sys/fs/pstore type pstore (rw,relatime) sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=3168040k) tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k) tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=802812k,mode=755) tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=802808k,mode=700,uid=1000,gid=1000) tmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,mode=755) udev on /dev type devtmpfs (rw,nosuid,relatime,size=3999244k,nr_inodes=999811,mode=755)
Por otro lado, con la opciones -n
o -g
es posible ordenar numéricamente en lugar de alfabéticamente. Por ejemplo, obtener los 20 procesos con más uso de CPU en un instante en particular:
emi@hal9000:~$ ps -eo %cpu,pid,cmd | sort -nr | head -n 20 18.4 2522 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 2 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 16.2 2411 /usr/lib/firefox-esr/firefox-esr 11.3 2471 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 1 -isForBrowser -prefsLen 1 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 4.9 1938 /usr/lib/xorg/Xorg -nolisten tcp -auth /var/run/slim.auth vt07 2.7 2583 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 7 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 2.3 2592 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 8 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 2.3 1773 /usr/sbin/cups-browsed 2.2 2525 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 3 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 1.2 2369 /usr/bin/pulseaudio --start 1.1 2552 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 4 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 0.8 2725 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 9 -isForBrowser -prefsLen 5944 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 0.8 1685 /usr/bin/dbus-daemon --system 0.7 2558 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 5 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 0.7 1710 avahi-daemon: running [hal9000.local] 0.6 4880 geany /tmp/archivo.txt 0.5 2566 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 6 -isForBrowser -prefsLen 137 -prefMapSize 185705 -parentBuildID 20191203235607 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true tab 0.4 2904 /usr/lib/firefox-esr/firefox-esr -contentproc -parentBuildID 20191203235607 -prefsLen 6972 -prefMapSize 185705 -greomni /usr/lib/firefox-esr/omni.ja -appomni /usr/lib/firefox-esr/browser/omni.ja -appdir /usr/lib/firefox-esr/browser 2411 true rdd 0.4 2126 xfwm4 --display :0.0 --sm-client-id 270e77b10-a968-4637-8095-d44ed19946b1 0.1 3161 xfce4-terminal --drop-down 0.1 2298 /usr/lib/x86_64-linux-gnu/xfce4/panel/wrapper-2.0 /usr/lib/x86_64-linux-gnu/xfce4/panel/plugins/libpulseaudio-plugin.so 4 20971554 pulseaudio PulseAudio Plugin Adjust the audio volume of the PulseAudio sound system
Esta opción interpreta el primer campo de cada línea como un valor numérico entero o real.
Más aún, la opción -h
permite ordenar por valores numéricos con unidades amigables como MB, KB, etc. Si quisiéramos ordenar los sistemas de archivo por uso de disco, simplemente personalizar la salida de df
y emplear esta opción:
emi@hal9000:~$ df -h Filesystem Size Used Avail Use% Mounted on udev 3.9G 0 3.9G 0% /dev tmpfs 784M 988K 784M 1% /run /dev/sda1 92G 6.9G 80G 8% / tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 3.1G 83M 3.0G 3% /dev/shm /dev/sda4 1.4T 319G 979G 25% /data /dev/sda3 366G 50G 298G 15% /home tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup none 3.9G 8.0K 3.9G 1% /run/user/1000
Se obtiene un listado de sistemas de archivo ordenados por espacio disponible, de menor a mayor:
emi@hal9000:~$ df -h --output=avail,source,target | sort -h Avail Filesystem Mounted on 5.0M tmpfs /run/lock 784M tmpfs /run 3.0G tmpfs /dev/shm 3.9G none /run/user/1000 3.9G tmpfs /sys/fs/cgroup 3.9G udev /dev 80G /dev/sda1 / 298G /dev/sda3 /home 979G /dev/sda4 /data
Para más información, consultar las páginas de manual de shuf
y sort
:
man shuf man sort