Aquí hay un fragmento de un libro futuro, Herramientas y prácticas básicas para un desarrollador de software novato, de Balthazar Ruberol y Etienne Broad . El libro debería ayudar a educar a la generación más joven de desarrolladores. Se tratarán temas tales como el dominio de la consola, la configuración y el trabajo de manera eficiente en la consola de comandos, control de versiones de código usando git
conceptos básicos de SQL, como herramientas Make
, jq
y expresiones regulares, fundamentos de la creación de redes, así como las mejores prácticas para el desarrollo de software y la colaboración. Los autores están trabajando duro en este proyecto y están invitando a todos a participar en la lista de correo .Contenido
Procesamiento de texto de shell
Una de las razones que hacen que el shell de comandos sea una herramienta invaluable es la gran cantidad de comandos de procesamiento de texto y la capacidad de combinarlos fácilmente en la tubería, creando plantillas de procesamiento complejas. Estos comandos hacen que muchas tareas sean triviales para analizar texto y datos, convertir datos entre diferentes formatos, filtrar cadenas, etc.Al trabajar con datos de texto, el principio principal es dividir cualquier problema complejo en muchos más pequeños, y resolver cada uno de ellos utilizando una herramienta especializada.Haga que cada programa haga una cosa bien: los fundamentos de la filosofía de Unix
Los ejemplos en este capítulo pueden parecer un poco exagerados a primera vista, pero esto se hace a propósito. Cada una de las herramientas está diseñada para resolver un pequeño problema. Sin embargo, cuando se combinan, se vuelven extremadamente poderosos.Analizaremos algunos de los comandos de procesamiento de texto más comunes y útiles en el shell de comandos y demostraremos los flujos de trabajo reales que los conectan entre sí. Sugiero mirar el maná de estos equipos para ver todas las posibilidades a tu disposición.Un archivo CSV de ejemplo está disponible en línea . Puede descargarlo para consultar el material.
gato
El comando se cat
utiliza para compilar una lista de uno o más archivos y mostrar su contenido en la pantalla.$ cat Documents/readme
Thanks again for reading this book!
I hope you're following so far!
$ cat Documents/computers
Computers are not intelligent
They're just fast at making dumb things.
$ cat Documents/readme Documents/computers
Thanks again for reading this book!
I hope you are following so far!
Computers are not intelligent
They're just fast at making dumb things.
cabeza
head
imprime las primeras n líneas en el archivo. Esto puede ser muy útil para buscar un archivo de estructura y formato desconocidos sin llenar toda la consola con un montón de texto.$ head -n 2 metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
mysql.galera.wsrep_cluster_size,gauge,,node,,The current number of nodes in the Galera cluster.,0,mysql,galera cluster size
Si -n
no se especifica, head
imprime las primeras diez líneas del archivo o flujo de entrada especificado.cola
tail
- un análogo head
, solo muestra las últimas n líneas en el archivo.$ tail -n 1 metadata.csv
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries
Si desea imprimir todas las líneas ubicadas después de la enésima línea (incluida), puede usar el argumento -n +n
.$ tail -n +42 metadata.csv
mysql.replication.slaves_connected,gauge,,,,Number of slaves connected to a replication master.,0,mysql,slaves connected
mysql.performance.queries,gauge,,query,second,The rate of queries.,0,mysql,queries
Hay 43 líneas en nuestro archivo, por lo tanto, tail -n +42
solo genera las líneas 42 y 43.Si -n
no se especifica el parámetro , tail
generará las últimas diez líneas en el archivo o flujo de entrada especificado.tail -f
o tail --follow
mostrar las últimas líneas en el archivo y cada nueva línea a medida que se escriben en el archivo. Esto es muy útil para ver la actividad en tiempo real, por ejemplo, lo que se registra en los registros del servidor web, etc.baño
wc
(recuento de palabras) muestra el número de caracteres ( -c
), palabras ( -w
) o líneas ( -l
) en el archivo o flujo especificado.$ wc -l metadata.csv
43 metadata.csv
$ wc -w metadata.csv
405 metadata.csv
$ wc -c metadata.csv
5094 metadata.csv
Por defecto, se muestra todo lo anterior.$ wc metadata.csv
43 405 5094 metadata.csv
Si los datos de texto se canalizan o se redirigen a stdin
, solo se muestra el contador.$ cat metadata.csv | wc
43 405 5094
$ cat metadata.csv | wc -l
43
$ wc -w < metadata.csv
405
grep
grep
- Este es un cuchillo suizo que filtra las cuerdas de acuerdo con un patrón dado.Por ejemplo, podemos encontrar todas las apariciones de la palabra mutex en un archivo.$ grep mutex metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.mutex_spin_rounds,gauge,,event,second,The rate of mutex spin rounds.,0,mysql,mutex spin rounds
mysql.innodb.mutex_spin_waits,gauge,,event,second,The rate of mutex spin waits.,0,mysql,mutex spin waits
grep
puede procesar archivos especificados como argumentos o una secuencia de texto que se le pasa stdin
. Por lo tanto, podemos concatenar varios comandos grep
para filtrar aún más el texto. En el siguiente ejemplo, filtramos las líneas en nuestro archivo metadata.csv
para encontrar líneas que contengan tanto mutex como OS .$ grep mutex metadata.csv | grep OS
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
Consideremos algunas opciones grep
y su comportamiento.grep -v
Realiza la coincidencia inversa: filtra las cadenas que no coinciden con el patrón de argumento.$ grep -v gauge metadata.csv
metric_name,metric_type,interval,unit_name,per_unit_name,description,orientation,integration,short_name
grep -i
Realiza coincidencias entre mayúsculas y minúsculas. El siguiente ejemplo se grep -i os
encuentra tanto OS y OS .$ grep -i os metadata.csv
mysql.innodb.mutex_os_waits,gauge,,event,second,The rate of mutex OS waits.,0,mysql,mutex os waits
mysql.innodb.os_log_fsyncs,gauge,,write,second,The rate of fsync writes to the log file.,0,mysql,log fsyncs
grep -l
Enumera archivos que contienen una coincidencia.$ grep -l mysql metadata.csv
metadata.csv
El equipo grep -c
cuenta cuántas veces se encontró una muestra.$ grep -c select metadata.csv
3
grep -r
busca archivos de forma recursiva en el directorio de trabajo actual y todos sus subdirectorios.$ grep -r are ~/Documents
/home/br/Documents/computers:Computers are not intelligent
/home/br/Documents/readme:I hope you are following so far!
grep -w
muestra solo palabras completas coincidentes.$ grep follow ~/Documents/readme
I hope you are following so far!
$ grep -w follow ~/Documents/readme
$
cortar
cut
extrae parte del archivo (o, como de costumbre, la secuencia de entrada). El comando define el separador de campo (que separa las columnas) usando la opción -d
, y los números de columna para recuperar usando la opción -f
.Por ejemplo, el siguiente comando recupera la primera columna de las últimas cinco líneas de nuestro archivo CSV.$ tail -n 5 metadata.csv | cut -d , -f 1
mysql.performance.user_time
mysql.replication.seconds_behind_master
mysql.replication.slave_running
mysql.replication.slaves_connected
mysql.performance.queries
Como estamos tratando con CSV, las columnas están separadas por una coma, y la opción es responsable de recuperar la primera columna -f 1
.Se puede seleccionar la primera y segunda columnas utilizando la opción -f 1,2
.$ tail -n 5 metadata.csv | cut -d , -f 1,2
mysql.performance.user_time,gauge
mysql.replication.seconds_behind_master,gauge
mysql.replication.slave_running,gauge
mysql.replication.slaves_connected,gauge
mysql.performance.queries,gauge
pegar
paste
combina dos archivos diferentes en un archivo de varias columnas.$ cat ingredients
eggs
milk
butter
tomatoes
$ cat prices
1$
1.99$
1.50$
2$/kg
$ paste ingredients prices
eggs 1$
milk 1.99$
butter 1.50$
tomatoes 2$/kg
Por defecto, se paste
utiliza un delimitador de pestaña, pero se puede cambiar mediante el parámetro -d
.$ paste ingredients prices -d:
eggs:1$
milk:1.99$
butter:1.50$
tomatoes:2$/kg
Otro caso de uso común paste
es combinar todas las líneas en una secuencia o archivo usando el delimitador especificado, usando una combinación de -s
y -d
.$ paste -s -d, ingredients
eggs,milk,butter,tomatoes
Si un parámetro se especifica como un archivo de entrada -
, se leerá en su lugar stdin
.$ cat ingredients | paste -s -d, -
eggs,milk,butter,tomatoes
ordenar
El comando sort
realmente clasifica los datos (en el archivo o flujo de entrada especificado).$ cat ingredients
eggs
milk
butter
tomatoes
salt
$ sort ingredients
butter
eggs
milk
salt
tomatoes
sort -r
realiza la clasificación inversa.$ sort -r ingredients
tomatoes
salt
milk
eggs
butter
sort -n
Ordena los campos por su valor aritmético.$ cat numbers
0
2
1
10
3
$ sort numbers
0
1
10
2
3
$ sort -n numbers
0
1
2
3
10
uniq
uniq
Detecta y filtra líneas idénticas adyacentes en el archivo o flujo de entrada especificado.$ cat duplicates
and one
and one
and two
and one
and two
and one, two, three
$ uniq duplicates
and one
and two
and one
and two
and one, two, three
Como solo uniq
filtra las líneas adyacentes , es posible que aún queden duplicados en nuestros datos. Para filtrar las mismas líneas de un archivo, primero debe ordenar su contenido.$ sort duplicates | uniq
and one
and one, two, three
and two
uniq -c
al comienzo de cada línea inserta el número de sus ocurrencias.$ sort duplicates | uniq -c
3 and one
1 and one, two, three
2 and two
uniq -u
Muestra solo cadenas únicas.$ sort duplicates | uniq -u
and one, two, three
Nota. uniq
Es especialmente útil en combinación con la clasificación, ya que la tubería le | sort | uniq
permite eliminar todas las líneas duplicadas en un archivo o secuencia.
awk
awk
- Esto es un poco más que una simple herramienta de procesamiento de texto: de hecho, tiene un lenguaje de programación completo . Lo que es awk
realmente bueno es dividir archivos en columnas, y lo hace con un brillo especial cuando los espacios y las pestañas se mezclan en los archivos.$ cat -t multi-columns
John Smith Doctor^ITardis
Sarah-James Smith^I Companion^ILondon
Rose Tyler Companion^ILondon
Nota. cat -t
muestra pestañas como ^I
.
Como puede ver, las columnas están separadas por espacios o pestañas, y no siempre por el mismo número de espacios. cut
es inútil aquí porque funciona con un solo carácter separador. Pero awk
es fácil lidiar con un archivo así.awk '{ print $n }'
muestra la enésima columna en el texto.$ cat multi-columns | awk '{ print $1 }'
John
Sarah-James
Rose
$ cat multi-columns | awk '{ print $3 }'
Doctor
Companion
Companion
$ cat multi-columns | awk '{ print $1,$2 }'
John Smith
Sarah-James Smith
Rose Tyler
Aunque es awk
capaz de mucho más, la salida de los altavoces es probablemente el 99% de los casos de uso en mi caso personal.Nota. { print $NF }
muestra la última columna en una fila.
tr
tr
significa traducir . Este comando reemplaza un personaje con otro. Funciona con caracteres o clases de caracteres como minúsculas, mecanografiadas, espacios, alfanuméricos, etc.En la entrada estándar, tr <char1> <char2>
reemplaza todas las apariciones de <char1> con <char2>.$ echo "Computers are fast" | tr a A
computers Are fAst
tr
puede traducir clases de caracteres usando notación [:class:]
. En la página del manual se describe una lista completa de las clases disponibles tr
, pero aquí se muestran algunas.[:space:]
representa todo tipo de espacios, desde espacios simples hasta pestañas o líneas nuevas.$ echo "computers are fast" | tr '[:space:]' ','
computers,are,fast,%
Todos los caracteres, como los espacios, están separados por comas. Tenga en cuenta que el carácter %
al final de la salida indica la ausencia de una nueva línea de terminación. De hecho, este personaje también se convierte en una coma.[:lower:]
representa todos los caracteres en minúscula y [:upper:]
todos los caracteres en mayúscula. Por lo tanto, la transformación entre ellos se vuelve trivial.$ echo "computers are fast" | tr '[:lower:]' '[:upper:]'
COMPUTERS ARE FAST
$ echo "COMPUTERS ARE FAST" | tr '[:upper:]' '[:lower:]'
computers are fast
tr -c SET1 SET2
convierte cualquier carácter no incluido en SET1 en caracteres en SET2. En el siguiente ejemplo, todos los caracteres, excepto las vocales indicadas, se reemplazan con espacios.$ echo "computers are fast" | tr -c '[aeiouy]' ' '
o u e a e a
tr -d
Elimina los caracteres especificados, pero no los reemplaza. Este es el equivalente tr <char> ''
.$ echo "Computers Are Fast" | tr -d '[:lower:]'
C A F
tr
También puede reemplazar rangos de caracteres, por ejemplo, todas las letras entre una y e o todos los números entre 1 y 8, usando la notación s-e
, en donde s
es el carácter de partida, y e
es el final.$ echo "computers are fast" | tr 'a-e' 'x'
xomputxrs xrx fxst
$ echo "5uch l337 5p34k" | tr '1-4' 'x'
5uch lxx7 5pxxk
El comando tr -s string1
comprime todas las apariciones múltiples de caracteres string1
en una sola. Uno de los usos más útiles tr -s
es reemplazar múltiples espacios consecutivos con uno.$ echo "Computers are fast" | tr -s ' '
Computers are fast
doblez
El comando fold
contrae todas las líneas de entrada al ancho especificado. Por ejemplo, puede ser útil asegurarse de que el texto se ajuste a pantallas pequeñas. Entonces, fold -w n
apila cadenas de ancho n caracteres.$ cat ~/Documents/readme | fold -w 16
Thanks again for
reading this bo
ok!
I hope you're fo
llowing so far!
El comando fold -s
romperá líneas solo en caracteres de espacio. Se puede combinar con el anterior para limitar la cadena al número especificado de caracteres.Thanks again
for reading
this book!
I hope you're
following so
far!
sed
sed
Es un editor de flujo no interactivo que se utiliza para convertir texto en el flujo de entrada línea por línea. Como entrada, ya sea un archivo o, o stdin
, en la salida, ya sea un archivo o stdout
.Los comandos del editor pueden incluir una o más direcciones , una función y parámetros . Por lo tanto, los comandos son los siguientes:[address[,address]]function[arguments]
Aunque sed
realiza muchas funciones, solo consideraremos reemplazar el texto como uno de los casos de uso más comunes.Reemplazo de texto
El comando de reemplazo es el sed
siguiente:s/PATTERN/REPLACEMENT/[options]
Ejemplo : reemplazar la primera instancia de una palabra en cada línea de un archivo:$ cat hello
hello hello
hello world!
hi
$ cat hello | sed 's/hello/Hey I just met you/'
Hey I just met you hello
Hey I just met you world
hi
Vemos que en la primera línea solo se reemplaza la primera instancia hello
. Para reemplazar todas las ocurrencias hello
en todas las líneas, puede usar la opción g
(significa global ).$ cat hello | sed 's/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
sed
le permite usar cualquier delimitador excepto /
, lo que mejora especialmente la legibilidad si hay barras en los argumentos del comando.$ cat hello | sed 's@hello@Hey I just met you@g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
La dirección le dice al editor en qué línea o rango de líneas realizar la sustitución.$ cat hello | sed '1s/hello/Hey I just met you/g'
Hey I just met you hello
hello world
hi
$ cat hello | sed '2s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
La dirección 1
indica reemplazar hello
en Hey I just met you
la primera línea. Podemos especificar el rango de direcciones en la notación <start>,<end>
, donde <end>
puede ser el número de línea o $
, es decir, la última línea del archivo.$ cat hello | sed '1,2s/hello/Hey I just met you/g'
Hey I just met you Hey I just met you
Hey I just met you world
hi
$ cat hello | sed '2,3s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
$ cat hello | sed '2,$s/hello/Hey I just met you/g'
hello hello
Hey I just met you world
hi
Por defecto, sed
produce el resultado en sí mismo stdout
, pero también puede editar el archivo original con la opción -i
.$ sed -i '' 's/hello/Bonjour/' sed-data
$ cat sed-data
Bonjour hello
Bonjour world
hi
Nota. En Linux, lo suficiente -i
. Pero en macOS, el comportamiento del comando es ligeramente diferente, por lo -i
que debe agregarlo inmediatamente después ''
.
Ejemplos reales
Filtrado CSV con grep y awk
$ grep -w gauge metadata.csv | awk -F, '{ if ($4 == "query") { print $1, "per", $5 } }'
mysql.performance.com_delete per second
mysql.performance.com_delete_multi per second
mysql.performance.com_insert per second
mysql.performance.com_insert_select per second
mysql.performance.com_replace_select per second
mysql.performance.com_select per second
mysql.performance.com_update per second
mysql.performance.com_update_multi per second
mysql.performance.questions per second
mysql.performance.slow_queries per second
mysql.performance.queries per second
En este ejemplo grep
, el archivo metadata.csv
primero filtra las líneas que contienen la palabra gauge
, luego aquellas con la query
cuarta columna, y muestra el nombre de la métrica (primera columna) con el valor correspondiente per_unit_name
(quinta columna).Muestra la dirección IPv4 asociada con la interfaz de red.
$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38
El comando ifconfig <interface name>
muestra información sobre la interfaz de red especificada. Por ejemplo:en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 19:64:92:de:20:ba
inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active
Luego corre grep
hacia inet
, eso producirá dos líneas de correspondencia.$ ifconfig en0 | grep inet
inet6 fe80::8a3:a1cb:56ae:7c7c%en0 prefixlen 64 secured scopeid 0x7
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
Luego, usando grep -v
excluir la línea con ipv6
.$ ifconfig en0 | grep inet | grep -v inet6
inet 192.168.0.38 netmask 0xffffff00 broadcast 192.168.0.255
Finalmente, con la ayuda, awk
solicitamos la segunda columna en esta fila: esta es la dirección IPv4 asociada con nuestra interfaz de red en0
.$ ifconfig en0 | grep inet | grep -v inet6 | awk '{ print $2 }'
192.168.0.38
Nota. Me ofrecieron reemplazar con grep inet | grep -v inet6
un equipo tan confiable awk
:
$ ifconfig en0 | awk ' $1 == "inet" { print $2 }'
192.168.0.38
Es más corto y está específicamente dirigido a IPv4 con la condición $1 == "inet"
.
Recuperando un valor de un archivo de configuración
$ grep 'editor =' ~/.gitconfig | cut -d = -f2 | sed 's/ //g'
/usr/bin/vim
En el archivo de configuración de git del usuario actual, busque el valor editor =
, recorte el carácter =
, extraiga la segunda columna y elimine todos los espacios.$ grep 'editor =' ~/.gitconfig
editor = /usr/bin/vim
$ grep 'editor =' ~/.gitconfig | cut -d'=' -f2
/usr/bin/vim
$ grep 'editor =' ~/.gitconfig | cut -d'=' -f2 | sed 's/ //'
/usr/bin/vim
Extraer IP de un archivo de registro
El siguiente código real busca un mensaje en el registro de la base de datos Too many connections from
(seguido de una dirección IP) y muestra los diez intrusos principales.$ grep 'Too many connections from' db.log | \
awk '{ print $12 }' | \
sed 's@/@@' | \
sort | \
uniq -c | \
sort -rn | \
head -n 10 | \
awk '{ print $2 }'
10.11.112.108
10.11.111.70
10.11.97.57
10.11.109.72
10.11.116.156
10.11.100.221
10.11.96.242
10.11.81.68
10.11.99.112
10.11.107.120
Veamos qué hace esta tubería. Primero, cómo se ve la línea en el registro.$ grep "Too many connections from" db.log | head -n 1
2020-01-01 08:02:37,617 [myid:1] - WARN [NIOServerCxn.Factory:1.2.3.4/1.2.3.4:2181:NIOServerCnxnFactory@193] - Too many connections from /10.11.112.108 - max is 60
Luego awk '{ print $12 }'
extrae la dirección IP de la cadena.$ grep "Too many connections from" db.log | awk '{ print $12 }'
/10.11.112.108
...
El comando sed 's@/@@'
elimina la barra diagonal inicial.$ grep "Too many connections from" db.log | awk '{ print $12 }' | sed 's@/@@'
10.11.112.108
...
Nota. Como vimos anteriormente, sed
puede usar cualquier separador en. Aunque generalmente se usa como separador /
, aquí estamos reemplazando este carácter en particular, lo que perjudicará ligeramente la legibilidad de la expresión de sustitución.
sed 's/\///'
sort | uniq -c
clasifica las direcciones IP en orden lexicográfico y luego elimina los duplicados, agregando el número de entradas antes de cada dirección IP.$ grep 'Too many connections from' db.log | \
awk '{ print $12 }' | \
sed 's@/@@' | \
sort | \
uniq -c
1379 10.11.100.221
1213 10.11.103.168
1138 10.11.105.177
946 10.11.106.213
1211 10.11.106.4
1326 10.11.107.120
...
sort -rn | head -n 10
ordena las líneas por el número de ocurrencias, numéricamente y en orden inverso, de modo que los infractores principales se muestren primero, de los cuales se muestran 10 líneas. El último comando awk { print $2 }
recupera las direcciones IP.$ grep 'Too many connections from' db.log | \
awk '{ print $12 }' | \
sed 's@/@@' | \
sort | \
uniq -c | \
sort -rn | \
head -n 10 | \
awk '{ print $2 }'
10.11.112.108
10.11.111.70
10.11.97.57
10.11.109.72
10.11.116.156
10.11.100.221
10.11.96.242
10.11.81.68
10.11.99.112
10.11.107.120
Renombrar una función en el archivo fuente
Imagine que estamos trabajando en un proyecto y nos gustaría cambiar el nombre de la función (o clase, variable, etc.) en el archivo fuente. Puede hacer esto con un comando sed -i
que reemplaza directamente en el archivo original.$ cat izk/utils.py
def bool_from_str(s):
if s.isdigit():
return int(s) == 1
return s.lower() in ['yes', 'true', 'y']
$ sed -i 's/def bool_from_str/def is_affirmative/' izk/utils.py
$ cat izk/utils.py
def is_affirmative(s):
if s.isdigit():
return int(s) == 1
return s.lower() in ['yes', 'true', 'y']
Nota. En macOS, sed -i
use en su lugar sed -i ''
.
Sin embargo, cambiamos el nombre de la función solo en el archivo original. Esto interrumpirá la importación bool_from_str
en cualquier otro archivo ya que esta función ya no está definida. Necesitamos encontrar una manera de cambiar el nombre de bool_from_str
nuestro proyecto. Esto se puede lograr usando comandos grep
, sed
así como bucles for
o usando xargs
.Profundización: ciclos for
yxargs
Para reemplazar todas las ocurrencias en nuestro proyecto bool_from_str
, primero debe encontrarlas recursivamente con grep -r
.$ grep -r bool_from_str .
./tests/test_utils.py:from izk.utils import bool_from_str
./tests/test_utils.py:def test_bool_from_str(s, expected):
./tests/test_utils.py: assert bool_from_str(s) == expected
./izk/utils.py:def bool_from_str(s):
./izk/prompt.py:from .utils import bool_from_str
./izk/prompt.py: default = bool_from_str(os.environ[envvar])
Como solo estamos interesados en archivos con coincidencias, también debe usar la opción -l/--files-with-matches
:-l, --files-with-matches
Only the names of files containing selected lines are written to standard out-
put. grep will only search a file until a match has been found, making
searches potentially less expensive. Pathnames are listed once per file
searched. If the standard input is searched, the string ``(standard input)''
is written.
$ grep -r --files-with-matches bool_from_str .
./tests/test_utils.py
./izk/utils.py
./izk/prompt.py
Entonces podemos usar el comando xargs
para llevar a cabo acciones desde cada línea de la salida (es decir, todos los archivos que contienen la línea bool_from_str
).$ grep -r --files-with-matches bool_from_str . | \
xargs -n 1 sed -i 's/bool_from_str/is_affirmative/'
La opción -n 1
indica que cada línea en la salida debe ejecutar un comando separado sed
.Luego se ejecutan los siguientes comandos:$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py
Si el comando con el que llamas xargs
(en nuestro caso sed
) admite múltiples argumentos, entonces debes descartar el argumento -n 1
por rendimiento.grep -r --files-with-matches bool_from_str . | xargs sed -i 's/bool_from_str/is_affirmative/'
Este comando se ejecutará$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py ./izk/utils.py ./izk/prompt.py
Nota. De la sinopsis sed
en la página del manual, se puede ver que el equipo puede tomar varios argumentos.
SYNOPSIS
sed [-Ealn] command [file ...]
sed [-Ealn] [-e command] [-f command_file] [-i extension] [file ...]
De hecho, como vimos en el capítulo anterior, file ...
significa que se aceptan varios argumentos, que son nombres de archivos.
Vemos que se hacen reemplazos para todas las ocurrencias bool_from_str
.$ grep -r is_affirmative .
./tests/test_utils.py:from izk.utils import is_affirmative
./tests/test_utils.py:def test_is_affirmative(s, expected):
./tests/test_utils.py: assert is_affirmative(s) == expected
./izk/utils.py:def is_affirmative(s):
./izk/prompt.py:from .utils import is_affirmative
./izk/prompt.py: default = is_affirmative(os.environ[envvar])
Como suele suceder, hay varias formas de lograr el mismo resultado. En cambio, xargs
podríamos usar bucles for
para iterar sobre las líneas de la lista y tomar medidas sobre cada elemento. Estos bucles tienen la siguiente sintaxis:for item in list; do
command $item
done
Si envolvemos nuestro mando grep
en $()
, a continuación, la cáscara se ejecutará en un subnivel , el resultado de que luego se repiten en un bucle for
.$ for file in $(grep -r --files-with-matches bool_from_str .); do
sed -i 's/bool_from_str/is_affirmative/' $file
done
Este comando se ejecutará$ sed -i 's/bool_from_str/is_affirmative/' ./tests/test_utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/utils.py
$ sed -i 's/bool_from_str/is_affirmative/' ./izk/prompt.py
La sintaxis del bucle for
me parece más clara que eso xargs
, pero este último puede ejecutar comandos en paralelo utilizando parámetros -P n
, donde n
es el número máximo de comandos paralelos ejecutados al mismo tiempo, lo que puede proporcionar una ganancia de rendimiento.Resumen
Todas estas herramientas abren todo un mundo de posibilidades, ya que le permiten extraer y transformar datos, creando canalizaciones enteras de equipos que nunca tuvieron la intención de trabajar juntos. Cada uno de ellos realiza una función relativamente pequeña (clasificación sort
, combinación cat
, filtros grep
, edición sed
, corte cut
, etc.).Cualquier tarea que incluya texto puede reducirse a una tubería de tareas más pequeñas, cada una de las cuales realiza una acción simple y transfiere su salida a la siguiente tarea.Por ejemplo, si queremos saber cuántas direcciones IP únicas hay en el archivo de registro, y para que estas direcciones IP siempre aparezcan en la misma columna, entonces podemos ejecutar la siguiente secuencia de comandos:grep
cadenas que coinciden con el patrón de cadenas con direcciones IP
- encuentre la columna con la dirección IP, extráigala con
awk
- ordenar la lista de direcciones IP usando
sort
- eliminar duplicados adyacentes con
uniq
- cuente el número de líneas (es decir, direcciones IP únicas) usando
wc -l
Dado que hay muchas herramientas de procesamiento de texto nativas y de terceros, también hay muchas formas de resolver cualquier problema.Los ejemplos en este artículo fueron exagerados, pero le sugiero que lea el increíble artículo "Las herramientas de línea de comandos pueden ser 235 veces más rápidas que su clúster Hadoop" para tener una idea de cuán útiles y poderosos son realmente estos comandos y qué problemas reales ellos pueden decidir.Que sigue
- Cuente la cantidad de archivos y directorios ubicados en su directorio de inicio.
- .
- , .
- . .
« » (Essential Tools and Practices for the Aspiring Software Developer) , . , , , , git
, SQL, Make
, jq
, , .
, !