- 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
Resultados $ ./test.sh using cut real 0m0.950s user 0m0.012s sys 0m0.232s using
¡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
Resultado $ ./test.sh $ ./test.sh using cut real 0m0.827s user 0m0.004s sys 0m0.208s using
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"
Es opcionalPor 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:
$
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.