Docena de trucos con Linux Shell que podrían ahorrarle tiempo



  • En primer lugar, puedes leer este artículo en ruso aquí .

Una tarde, mientras leía Dominando las expresiones regulares de Jeffrey Friedl , me di cuenta de que incluso si tiene toda la documentación y mucha experiencia, podría haber muchos trucos desarrollados por diferentes personas y encarcelados por ellos mismos. Todas las personas son diferentes. Y las técnicas que son obvias para ciertas personas pueden no ser obvias para otros y parecer una especie de magia extraña para una tercera persona. Por cierto, ya describí varios de estos momentos aquí (en ruso) .

Para el administrador o el usuario, la línea de comandos no es solo una herramienta que puede hacer todo, sino también una herramienta altamente personalizada que podría desarrollarse para siempre. Recientemente hubo un artículo traducido sobre algunos trucos útiles en CLI. Pero siento que el traductor no tiene suficiente experiencia con CLI y no siguió los trucos descritos, por lo que muchas cosas importantes podrían perderse o malinterpretarse.

Under the cut: una docena de trucos en el shell de Linux desde mi experiencia personal.

Nota: Todos los scripts y ejemplos en el artículo se simplificaron especialmente tanto como sea posible, por lo que quizás pueda encontrar varios trucos que parecen completamente inútiles, tal vez esta sea la razón. Pero, en cualquier caso, ¡comparte tu opinión en los comentarios!

1. Cadena dividida con expansiones variables


La gente a menudo usa cut o incluso awk solo para restar una parte de la cuerda por patrón o con separadores.
Además, muchas personas usan la operación de subcadena bash usando $ {VARIABLE: start_position: length}, que funciona muy rápido.

Pero bash proporciona una forma poderosa de manipular cadenas de texto usando #, ##,% y %%: se llama expansiones de variables bash .
Con esta sintaxis, puede cortar lo necesario por el patrón sin ejecutar comandos externos, por lo que funcionará realmente rápido.

El siguiente ejemplo muestra cómo obtener la tercera columna (shell) de la cadena donde los valores están separados por dos puntos "username: homedir: shell" usando cut o usando expansiones variables (usamos la máscara *: y el comando ##, que significa: cut todos los caracteres a la izquierda hasta el último colon encontrado):

$ STRING="username:homedir:shell" $ echo "$STRING"|cut -d ":" -f 3 shell $ echo "${STRING##*:}" shell 

La segunda opción no inicia el proceso secundario ( corte ) y no utiliza tuberías en absoluto, lo que debería funcionar mucho más rápido. Y si está utilizando el subsistema bash en ventanas, donde las tuberías apenas se mueven, la diferencia de velocidad será significativa .

Veamos un ejemplo en Ubuntu: ejecute nuestro comando en un bucle 1000 veces

 $ cat test.sh #!/usr/bin/env bash STRING="Name:Date:Shell" echo "using cut" time for A in {1..1000} do cut -d ":" -f 3 > /dev/null <<<"$STRING" done echo "using ##" time for A in {1..1000} do echo "${STRING##*:}" > /dev/null done 

Resultados
 $ ./test.sh using cut real 0m0.950s user 0m0.012s sys 0m0.232s using ## real 0m0.011s user 0m0.008s sys 0m0.004s 

¡La diferencia es varias docenas de veces!

Por supuesto, el ejemplo anterior es demasiado artificial. En el ejemplo real no trabajaremos con una cadena estática, queremos leer un archivo real. Y para el comando ' cortar ', simplemente redirigimos / etc / passwd a él. En el caso de ##, tenemos que crear un bucle y leer el archivo usando el comando interno ' leer '. Entonces, ¿quién ganará este caso?

 $ cat test.sh #!/usr/bin/env bash echo "using cut" time for count in {1..1000} do cut -d ":" -f 7 </etc/passwd > /dev/null done echo "using ##" time for count in {1..1000} do while read do echo "${REPLY##*:}" > /dev/null done </etc/passwd done 
Resultado
 $ ./test.sh $ ./test.sh using cut real 0m0.827s user 0m0.004s sys 0m0.208s using ## real 0m0.613s user 0m0.436s sys 0m0.172s 
No hay comentarios =)

Un par de ejemplos más:

Extraiga el valor después del carácter igual:

 $ VAR="myClassName = helloClass" $ echo ${VAR##*= } helloClass 

Extraer texto entre corchetes:

 $ VAR="Hello my friend (enemy)" $ TEMP="${VAR##*\(}" $ echo "${TEMP%\)}" enemy 

2. Autocompletar Bash con pestaña


El paquete bash-complete es parte de casi todos los distributivos de Linux. Puede habilitarlo en /etc/bash.bashrc o /etc/profile.d/bash_completion.sh, pero generalmente ya está habilitado de forma predeterminada. En general, el autocompletado es uno de los primeros momentos convenientes en el shell de Linux que un recién llegado conoce en primer lugar.

Pero el hecho de que no todos usen todas las funciones de finalización de bash, y en mi opinión es completamente en vano. Por ejemplo, no todo el mundo sabe que el autocompletado funciona no solo con nombres de archivos, sino también con alias, nombres de variables, nombres de funciones y para algunos comandos, incluso con argumentos. Si profundiza en los scripts de autocompletado, que en realidad son scripts de shell, incluso puede agregar el autocompletado para su propia aplicación o script.
Pero volvamos a los alias.

No necesita editar la variable PATH o crear archivos en el directorio especificado para ejecutar el alias. Solo necesita agregarlos al perfil o script de inicio y ejecutarlos desde cualquier lugar.

Por lo general, estamos usando letras minúsculas para archivos y directorios en * nix, por lo que podría ser muy cómodo crear alias en mayúsculas; en ese caso, bash-complete adivinará su comando casi con una sola letra:

 $ alias TAsteriskLog="tail -f /var/log/asteriks.log" $ alias TMailLog="tail -f /var/log/mail.log" $ TA[tab]steriksLog $ TM[tab]ailLog 

3. Autocompletar Bash con pestaña - parte 2


Para casos más complicados, probablemente le gustaría poner sus scripts personales en $ HOME / bin.
Pero tenemos funciones en bash.

Las funciones no requieren ruta o archivos separados. Y (atención) bash-complete también funciona con funciones.

Creemos la función LastLogin en .profile (no olvide volver a cargar .profile):

 function LastLogin { STRING=$(last | head -n 1 | tr -s " " " ") USER=$(echo "$STRING"|cut -d " " -f 1) IP=$(echo "$STRING"|cut -d " " -f 3) SHELL=$( grep "$USER" /etc/passwd | cut -d ":" -f 7) echo "User: $USER, IP: $IP, SHELL=$SHELL" } 

(En realidad, no es importante lo que está haciendo esta función, es solo un script de ejemplo que podemos poner en el script separado o incluso en el alias, pero la función podría ser mejor) .

En la consola (tenga en cuenta que el nombre de la función tiene una primera letra mayúscula para acelerar la finalización de bash):

 $ L[tab]astLogin User: saboteur, IP: 10.0.2.2, SHELL=/bin/bash 

4.1. Datos sensibles


Si pone espacio antes de cualquier comando en la consola, no aparecerá en el historial de comandos, por lo que si necesita poner una contraseña de texto sin formato en el comando, es una buena manera de usar esta función; consulte el ejemplo a continuación, repita "hola" 2 " no aparecerá en la historia:

 $ echo "hello" hello $ history 2 2011 echo "hello" 2012 history 2 $ echo "my password secretmegakey" # there are two spaces before 'echo' my password secretmegakey $ history 2 2011 echo "hello" 2012 history 2 

Es opcional
Por lo general, está habilitado de manera predeterminada, pero puede configurar este comportamiento en la siguiente variable:

export HISTCONTROL = ignoreboth


4.2. Datos confidenciales en argumentos de línea de comando


Desea almacenar algunos scripts de shell en git para compartirlos entre servidores, o puede ser parte del script de inicio de la aplicación. Y desea que este script se conecte a la base de datos o haga cualquier otra cosa que requiera credenciales.

Por supuesto, es una mala idea almacenar las credenciales en el script en sí, porque git no es seguro.

Por lo general, puede usar variables, que ya se definieron en los entornos de destino, y su secuencia de comandos no contendrá las contraseñas en sí.

Por ejemplo, puede crear un script pequeño en cada entorno con 700 permisos y llamarlo usando el comando de origen del script principal:

 secret.sh PASSWORD=LOVESEXGOD 

 myapp.sh source ~/secret.sh sqlplus -l user/"$PASSWORD"@database:port/sid @mysqfile.sql 

Pero no es seguro.

Si alguien más puede iniciar sesión en su host, puede ejecutar el comando ps y ver su proceso sqlplus con todos los argumentos de la línea de comando, incluidas las contraseñas. Por lo tanto, las herramientas seguras generalmente deberían poder leer contraseñas / claves / datos confidenciales directamente de los archivos.

Por ejemplo, secure ssh simplemente no tiene opciones para proporcionar una contraseña en la línea de comandos. Pero él puede leer la clave ssh del archivo (y usted puede establecer permisos seguros en el archivo de clave ssh).

Y wget no seguro tiene una opción "- contraseña" que le permite proporcionar una contraseña en la línea de comandos. Y todo el tiempo wget se ejecutará, todos pueden ejecutar el comando ps y ver la contraseña que ha proporcionado.

Además, si tiene muchos datos confidenciales y desea controlarlos desde git, la única forma es el cifrado. Por lo tanto, coloca en cada entorno de destino solo la contraseña maestra y todos los demás datos que puede cifrar y poner en git. Y puede trabajar con datos cifrados desde la línea de comandos, utilizando la interfaz CLI de openssl. Aquí hay un ejemplo para cifrar y descifrar desde la línea de comandos:

El archivo secret.key contiene la clave maestra: una sola línea:

 $ echo "secretpassword" > secret.key; chmod 600 secret.key 

Usemos aes-256-cbc para encriptar una cadena:

 $ echo "string_to_encrypt" | openssl enc -pass file:secret.key -e -aes-256-cbc -a U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML 

Puede colocar esta cadena encriptada en cualquier archivo de configuración almacenado en git, o en cualquier otro lugar, sin secret.key es casi imposible descifrarlo.
Para descifrar ejecute el mismo comando simplemente reemplace -e con -d:

 $ echo 'U2FsdGVkX194R0GmFKCL/krYCugS655yLhf8aQyKNcUnBs30AE5lHN5MXPjjSFML' | openssl enc -pass file:secret.key -d -aes-256-cbc -a string_to_encrypt 

5. El comando grep


Todos deberían saber el comando grep. Y sé amigable con las expresiones regulares. Y a menudo puedes escribir algo como:

 tail -f application.log | grep -i error 

O incluso así:

 tail -f application.log | grep -i -P "(error|warning|failure)" 

Pero no olvide que grep tiene muchas opciones maravillosas. Por ejemplo -v, que revierte su búsqueda y muestra todos excepto los mensajes de "información":

 tail -f application.log | grep -v -i "info" 

Cosas adicionales:

La opción -P es muy útil, porque por defecto grep usa una "expresión regular básica:" bastante desactualizada, y -P habilita PCRE que incluso no sabe acerca de la agrupación.
-I ignora el caso.
--line-buffer almacena la línea inmediatamente en lugar de esperar a alcanzar el buffer estándar de 4k (útil para tail -f | grep).

Si conoce bien la expresión regular, con --only-matching / -o realmente puede hacer grandes cosas al cortar texto. Simplemente compare los siguientes dos comandos para extraer el shell de myuser:

 $ grep myuser /etc/passwd| cut -d ":" -f 7 $ grep -Po "^myuser(:.*){5}:\K.*" /etc/passwd 

El segundo comando parece más compilado, pero solo ejecuta grep en lugar de grep and cut , por lo que tomará menos tiempo ejecutarlo.

6. Cómo reducir el tamaño del archivo de registro


En * nix, si elimina el archivo de registro, que actualmente utiliza una aplicación, no solo puede eliminar todos los registros, sino que puede evitar que la aplicación escriba nuevos registros hasta que se reinicie.

Debido a que el descriptor de archivo no abre el nombre del archivo, sino la estructura iNode, y la aplicación continuará escribiendo en el descriptor de archivo en el archivo, que no tiene entrada de directorio, y dicho archivo se eliminará automáticamente después de que la aplicación se detenga por el sistema de archivos ( su aplicación puede abrir y cerrar el archivo de registro cada vez que quiera escribir algo para evitar tal problema, pero afecta el rendimiento ).

Entonces, cómo borrar el archivo de registro sin eliminarlo:

 echo "" > application.log 

O podemos usar el comando truncar:

 truncate --size=1M application.log 

Mencione que el comando truncar eliminará el resto del archivo, por lo que perderá los últimos eventos de registro. Consulte otro ejemplo de cómo almacenar las últimas 1000 líneas:

 echo "$(tail -n 1000 application.log)" > application.log 

PD En Linux tenemos el servicio estándar rotatelog. Puede agregar sus registros para truncar / rotar automáticamente o usar las bibliotecas de registros existentes que pueden hacerlo por usted (como log4j en java).

7. ¡ Watch te está mirando!


Hay una situación en la que está esperando que se termine algún evento. Por ejemplo, mientras otro usuario inicia sesión en el shell (ejecutas continuamente quién manda), o alguien debe copiar el archivo a tu máquina usando scp o ftp y estás esperando que se complete (repitiendo ls docenas de veces).

En tales casos, puede usar

 watch <command> 

Por defecto, se ejecutará cada 2 segundos con un borrado previo de pantalla hasta que se presione Ctrl + C. Puede configurar con qué frecuencia se debe ejecutar.

Es muy útil cuando desea ver registros en vivo.

8. Secuencia bash


Hay una construcción muy útil para crear rangos. Por ejemplo, en lugar de algo como esto:

 for srv in 1 2 3 4 5; do echo "server${srv}";done server1 server2 server3 server4 server5 

Puedes escribir lo siguiente:

 for srv in server{1..5}; do echo "$srv";done server1 server2 server3 server4 server5 

También puede usar el comando seq para generar rangos formateados. Por ejemplo, podemos usar seq para crear valores que se ajustarán automáticamente por ancho (00, 01 en lugar de 0, 1):

 for srv in $(seq -w 5 10); do echo "server${srv}";done server05 server06 server07 server08 server09 server10 

Otro ejemplo con la sustitución de comandos: renombrar archivos. Para obtener un nombre de archivo sin extensión, estamos usando el comando ' basename ':

 for file in *.txt; do name=$(basename "$file" .txt);mv $name{.txt,.lst}; done 

También aún más corto con '%':

 for file in *.txt; do mv ${file%.txt}{.txt,.lst}; done 

PD En realidad, para cambiar el nombre de los archivos, puedes probar la herramienta ' cambiar nombre ' que tiene muchas opciones.

Otro ejemplo: permite crear una estructura para un nuevo proyecto de Java:

 mkdir -p project/src/{main,test}/{java,resources} 

Resultado
 project/ !--- src/ |--- main/ | |-- java/ | !-- resources/ !--- test/ |-- java/ !-- resources/ 

9. cola, múltiples archivos, múltiples usuarios ...


He mencionado multitail para leer archivos y ver múltiples registros en vivo. Pero no se proporciona de manera predeterminada, y los permisos para instalar algo no siempre están disponibles.

Pero la cola estándar también puede hacerlo:

 tail -f /var/logs/*.log 

También recordemos acerca de los usuarios, que usan alias 'tail -f' para ver los registros de las aplicaciones.
Varios usuarios pueden ver archivos de registro simultáneamente usando 'tail -f'. Algunos de ellos no son muy precisos con sus sesiones. Podrían dejar 'tail -f' en segundo plano por alguna razón y olvidarse de eso.

Si se reinició la aplicación, hay estos procesos en ejecución 'tail -f' que observan que el archivo de registro inexistente puede bloquearse durante varios días o incluso meses.

Por lo general, no es un gran problema, pero no claramente.

En caso de que esté utilizando un alias para ver el registro, puede modificar este alias con la opción --pid:

 alias TFapplog='tail -f --pid=$(cat /opt/app/tmp/app.pid) /opt/app/logs/app.log' 

En ese caso, todas las colas se terminarán automáticamente cuando se reinicie la aplicación de destino.

10. Crear archivo con tamaño especificado


dd fue una de las herramientas más populares para trabajar con datos de bloque y binarios. Por ejemplo, crear un archivo de 1 MB lleno de cero será:

 dd if=/dev/zero of=out.txt bs=1M count=10 

Pero recomiendo usar Falocate :

 fallocate -l 10M file.txt 

En los sistemas de archivos, que admiten la función de asignación (xfs, ext4, Btrfs ...), Fallocate se ejecutará instantáneamente, a diferencia de la herramienta dd. Además, asignar significa asignación real de bloques, no crear un archivo de reserva.

11. xargs


Mucha gente conoce el comando popular xargs . Pero no todos ellos usan las siguientes dos opciones, que podrían mejorar enormemente su script.

Primero: puede obtener una lista muy larga de argumentos para procesar, y podría exceder la longitud de la línea de comando (por defecto ~ 4 kb).

Pero puede limitar la ejecución utilizando la opción -n, por lo que xargs ejecutará el comando varias veces, enviando un número específico de argumentos a la vez:

 $ # lets print 5 arguments and send them to echo with xargs: $ echo 1 2 3 4 5 | xargs echo 1 2 3 4 5 $ # now let's repeat, but limit argument processing by 3 per execution $ echo 1 2 3 4 5 | xargs -n 3 echo 1 2 3 4 5 

Adelante Procesar una lista larga puede llevar mucho tiempo, ya que se ejecuta en un solo hilo. Pero si tenemos varios núcleos, podemos decirle a xargs que se ejecute en paralelo:

 echo 1 2 3 4 5 6 7 8 9 10| xargs -n 2 -P 3 echo 

En el ejemplo anterior, le decimos a xargs que procese la lista en 3 hilos; cada hilo tomará y procesará 2 argumentos por ejecución. Si no sabe cuántos núcleos tiene, optimicemos esto usando " nproc ":

 echo 1 2 3 4 5 6 7 8 9 10 | xargs -n 2 -P $(nproc) echo 

12. dormir? mientras? leer!


En algún momento debes esperar varios segundos. O espere la entrada del usuario con lectura:

 read -p "Press any key to continue " -n 1 

Pero solo puede agregar la opción de tiempo de espera para leer el comando, y su secuencia de comandos se pausará durante una cantidad específica de segundos, pero en caso de ejecución interactiva, el usuario puede omitir fácilmente la espera.

 read -p "Press any key to continue (auto continue in 30 seconds) " -t 30 -n 1 

Entonces puedes olvidarte del comando sleep.

Sospecho que no todos mis trucos parecen interesantes, pero me pareció que una docena es un buen número para completar.

En este momento, me despido y agradeceré participar en la encuesta.

Por supuesto, siéntase libre de discutir lo anterior y compartir sus trucos geniales en los comentarios.

Source: https://habr.com/ru/post/444890/


All Articles