¡Esta es una revisión vieja del documento!
Tabla de Contenidos
Construcciones de CLI (Interfaz de línea de comandos) e información útil
El propósito de este artículo no es ser un tutorial de CLI, sino más bien ser una exposición de construcciones comunes utilizadas en shell scripting para lograr un objetivo de manera eficiente. También hay secciones que simplemente ayudan a entender un tema determinado.
Construye
rev | cut | rev
A menudo es útil revertir una cadena y luego usar cut. Por ejemplo, tome un paquete Slackware y obtenga su nombre:
echo dejavu-fonts-ttf-2.33-noarch-1 | rev | cut -d - -f 1-3 --complement | rev ls -1 /var/log/packages | rev | cut -d - -f 1-3 --complement | rev
O si desea obtener la ruta completa de un archivo, menos el sufijo.
echo /proc/config.gz | rev | cut -d. -f1 --complement | rev
Reemplazar un sufijo
Digamos que querías hacer un script de conversión de video y que necesitabas cambiar el sufijo.
input=test.mkv output="$(basename "$input" .mkv).avi"
find | xargs
Esta es una interacción especial entre find y xargs que permite tratar espacios en los nombres de archivos. Es muy rápido porque muchos comandos como rm
, rmdir
y shred
toman múltiples entradas de archivos en la línea de comandos. Una construcción genérica es algo como:
find . -type f -print0 | xargs -0 "$command"
Puede reemplazar $ command
con cualquier comando que necesite para ejecutar en los archivos siempre que sea compatible con la entrada de múltiples archivos. Si tiene una lista de archivos, aún puede conservar espacios:
tr '\n' '\0' < "$file" | xargs -0 "$command"
comm antes y después
Esta construcción es útil para aplicaciones de gestión de paquetes. Desde la página de manual de comm:
With no options, produce three-column output. Column one contains lines unique to FILE1, column two contains lines unique to FILE2, and column three contains lines common to both files.
Las opciones '-1'
'-2'
'-3
' suprimen las columnas respectivas. Supongamos que desea registrar los archivos que se agregaron a /usr
después de ejecutar el comando $ 1
:
# before, make install, after find /usr > "$tmp/before" $1 find /usr > "$tmp/after" # sort sort "$tmp/before" > "$tmp/before-sorted" sort "$tmp/after" > "$tmp/after-sorted" # create log comm -13 "$tmp/before-sorted" "$tmp/after-sorted" > "$log/$name"
Tenga en cuenta que comm requiere archivos ordenados. Aquí -1
suprime las líneas exclusivas de antes, -3
suprime las líneas presentes en ambos archivos, por lo que queda con la columna 2 que contiene archivos exclusivos después de los archivos agregados. A muchas personas les gustaría usar diff para comparar archivos, pero es principalmente para crear parches.
while read line
Esta construcción es común y es útil para leer archivos o ingresar una línea a la vez. Aquí hay un ejemplo que se puede usar para concatenar archivos divididos en orden:
base="$(echo "$@" | rev | cut -d. -f1 --complement | rev)" ls -1 "$base".* | sort -V | while read line do cat "$line" >> "$base" done
También tenga en cuenta que sort -V
es una clasificación de versión y es útil en los casos en que ls
ordena los sufijos de forma incorrecta. La forma habitual de evitar esto es nombrar sufijos numerados con 0
como file.001
, pero puede desbordarse y es por eso que sort -V
es útil.
for i in
Aquí hay un ejemplo para extraer todos los rpms en un directorio:
for i in *.rpm do rpm2cpio "$i" | cpio -id --quiet done
También puede usar seq
para hacer que i
sea un contador de bucle:
for i in $(seq 1 100) do echo "$i" done
Tenga en cuenta que no hay comillas alrededor de $ (seq)
porque de lo contrario, citaría la secuencia numérica completa y eso no funcionaría bien.
Enlaces externos
Comilla
Las comillas pueden parecer complicadas, y las razones de ello son oscuras, pero tiene un propósito y no es tan complicado.
Doble comillas
La razón para la comilla doble es para preservar espacios, como espacios en nombres de archivos. La doble cita de una variable o una sustitución de comando lo convierte en un solo argumento. Un ejemplo:
bash-4.2$ ls file with spaces.txt filewithoutspaces.txt bash-4.2$ rm -f file with spaces.txt bash-4.2$ ls file with spaces.txt filewithoutspaces.txt bash-4.2$ rm -f "file with spaces.txt" bash-4.2$ ls filewithoutspaces.txt bash-4.2$ rm -f filewithoutspaces.txt bash-4.2$ ls bash-4.2$
Claramente necesitas encomillar un archivo con espacios. Puede usar comillas simples aquí, porque no hay variables dentro de las comillas. No debes encomillar en este caso:
bash-4.2$ for i in $(seq 1 10); do printf "$i "; done; echo; 1 2 3 4 5 6 7 8 9 10 bash-4.2$ for i in "$(seq 1 10)"; do printf "$i "; done; echo; 1 2 3 4 5 6 7 8 9 10 bash-4.2$
Tampoco debe encomillar en ningún caso en que un comando requiera múltiples variables y se las asigne dentro de una variable encomillada. Una variable encomillada se toma entonces como el único argumento, en lugar de múltiples argumentos. Un ejemplo:
bash-4.2$ ls file with spaces.txt filewithoutspaces.txt bash-4.2$ file1="file with spaces.txt" bash-4.2$ file2="filewithoutspaces.txt" bash-4.2$ rm -f "$file1 $file2" bash-4.2$ ls file with spaces.txt filewithoutspaces.txt bash-4.2$ rm -f "$file1" "$file2" bash-4.2$ ls bash-4.2$
También tenga en cuenta que puede y debe encomillar dentro de las sustituciones de comandos, como se muestra en el ejemplo anterior “reemplazar un sufijo” y:
mkdir "$(basename "$(pwd)")"
Esto crea un directorio dentro del directorio actual llamado el mismo nombre que el directorio actual. Si pwd
se expande en algo con espacios, el comando funcionará.
Comilla simple
La razón para la comilla simple es para escapar caracteres especiales de la shell, mientras se los pasa a un comando para que pueda usarlos. Debe usar comillas simples para cada argumento pasado a otro programa que contenga caracteres de shell para que sean interpretados por ese programa y NO por el shell. Ejemplo:
bash-4.2$ find -name *.txt ./list.txt bash-4.2$ find -name '*.txt' ./list.txt ./results/002.txt ./results/006.txt ./results/013.txt ./results/wipe.txt bash-4.2$
Aquí el sehell se expande *
antes de encontrarla. Debe ingresar la entrada de comillas a awk
, find
, sed
y grep
, ya que cada uno de ellos utiliza caracteres especiales que se superponen con las del shell, y por lo tanto deben ser Protegido de la expansión del shell.
Enlaces externos
Regular expressions
Basic
.
matches any single character.\
escapes the next character.
.
using \.
if you want an actual .
bash-4.2$ cat test.txt testtxt test.txt bash-4.2$ sed 's/.txt//g' test.txt tes test bash-4.2$ sed 's/\.txt//g' test.txt testtxt test
[]
is a class and matches anything inside the brakets for a single character. Examples:[Yy]
matches Y or y.[a-z0-9]
includes a range, and in this case matches a through z and 0 through 9.[^a-z]
negates the range, so in this case it matches anything but a through z.
^
matches the beginning of a line. Example:^a
matches an a at the beginning of a line.$
matches the end of a line. Example:a$
matches an a at the end of a line.\<
matches the beginning of a word. Example:\<a
matches an a at the beginning of a word.\>
matches the end of a word. Example:a\>
matches an a at the end of a word.- Example:
\<[tT]he\>
matches the wordthe
orThe
.
*
matches any number of the previous character or nothing = no character. Example:[0-9]*
which will match any number of numbers..*
matches any number of anything.
Extended regular expressions
The following must be supported by the program for them to work. For example for grep you must run egrep
or grep -E
.
+
matches any number of the previous character, like*
, but there must be at least one to match, so it will not match nothing or no character.?
makes the previous character optional (it can be missing), and is matched at most once.(|)
acts like an OR statement. Example:(it|her|this)
matches any of those words.a{3}
matchesaaa
= 3 a's.a{4,8}
matches an a at least 4 times and at max 8 times, soaaaa
,aaaaa
,aaaaaa
,aaaaaaa
, andaaaaaaaa
.{0,}
=*
{1,}
=+
{,1}
=?
External Links
Useful commands and info
stat
Stat is the most accurate way to determine:
- File size in bytes:
stat -c '%s' file.txt
- File permissions in octal:
stat -c '%a' file.txt
awk variable defaults
An important point is that awk variables are set to zero by default. This may cause problems in some situtations. Example:
echo -ne '-321\n-14\n-1\n-34\n-4\n' | awk 'BEGIN{max=""}{if ($1 > max) max=$1; if ($1 < min) min=$1;}END{print min"\t"max}'
This works properly because max is set to an empty string and thus has a lower value than any number. Try removing the BEGIN clause and see what happens. Also note that adding min=“”
to the BEGIN clause fails as well.
no data directory test
You can use this to test if a directory contains no data. For example, it will say 0
if the directory only contains empty files and directories = no data.
du -s directory
cmp
This can compare two files byte by byte, and can be more useful than checksums. For example, after you burn a CD/DVD, you can run:
cmp slackware.iso /dev/sr0
It should say the following if the disk burned correctly:
cmp: EOF on slackware.iso
shell math
Remember that shell utilities like let
and expr
only do integer math. For floating point use either bc
or awk
.
shell GUI
There are numerous programs that allow you to create GUIs from a shell script.