Conceptos avanzados sistemas de ficheros en linux

Inodos

Ya todos sabemos que dentro del sistema de archivos de linux, que es una estructura jerarquica, tenemos principalmente dos tipos de estructuras, ficheros y directorios a demas dentro de estos directorios tenemos mas directorios (sub directorios) y dentro de esos subdirectorios hay mas archivos. Ademas estos archivos tienen un propietario, ciertos permisos entre otros datos.Cabe preguntarse, donde almacena toda esta informacion el sistema operativo? como sabe que un directorio esta dentro de cual otro?.Para responder a estas preguntas y a muchas otras tenemos que conocer unas estructuras llamada inodos.

Por ejemplo, creamos un fichero con touch fichero.txt y dentro escribimos “hola mundo”. Luego hacemos un ls -l y vemos algo asi:

drwxrwxr-x akerman    akerman    4096       Feb        19         09:12      akerman
drwx------  19         999        root       4096       Apr        11         13:37      data
drwxr-xr-x akerman    akerman    4096       Apr        25         12:32      Desktop
drwxr-xr-x akerman    akerman    4096       May        6          14:26      Documents
drwxr-xr-x akerman    akerman    4096       May        6          14:23      Downloads
-rw-rw-r-- akerman    akerman    12         May        9          09:04      fichero.txt

Todos esos datos adicionales,del propio fichero estan alamacenados en un inodo, ojo solos los metadatos el texto escrito dentro de el no es considerado un metadato, el texto en si mismo es considerado dato.

Todos los archivos y directorios que tengamos en nuetro sistema linux, va a tener tener un inodo asociado con sus metadatos correspondientes.

Cada inodo tiene un identificador unico con el cual referenciara a acada carpeta o archivo, por lo cual no usuara el nombre original del item para buscarlo, sino que sera este id.

Como saber cuantos inodos tenemos disponibles en nuetro sistema.

Hacemos df -i veremos algo como esto:

Filesystem       Inodes   IUsed    IFree IUse% Mounted on

tmpfs           8215010    1528  8213482    1% /run
/dev/sdb2      62447616 1172314 61275302    2% /
tmpfs           8215010     144  8214866    1% /dev/shm
tmpfs           8215010       7  8215003    1% /run/lock

Si vemos en la columna Inodes en nuestro sistema de archivos principal (montado en /) nos dice que tenemos 62447616 este seria el maximo de ficheros y directorios que podriamos tener, solo usados un 2%. Muchos de ellos ya vienen por defecto en el sistema.

Los inodos van referenciar los bloques dentro del disco donde se encuentra la infomacion del archivo. El texto “hola mundo” que creamos antes esta guardado en una direccion del disco, los inodos saben donde ir a buscarlo.

Por ejemplo si hacemos cat fichero.txt veremos que se imprime la informacion en consola , eso es gracias a los inodos que saben donde encontrarlo.

Tene en cuenta que el tamanio de nodos no tiene nada que ver con la cantidad de gigas de nuestro disco. Por lo cual, es posible que nos quedemos sin inodos antes que espacio en disco. Esto puede pasar si creamos muchos archivos chicos que no ocupan espacio en disco pero si que se le asigna un inodo.

Como saber el numero de inodo de un archivo en concreto y ver la informacion

Hacemos ls -i fichero.txt el flag -i le dice que queremos ver el numero de inodo.

25743601 fichero.txt

Si queremos ver en detalle que tiene ese nodo, podemos usar stat fichero.txt

Size: 12        	Blocks: 8          IO Block: 4096   regular file
Device: 8,18	Inode: 25743601    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/ akerman)   Gid: ( 1000/ akerman)
Access: 2024-05-09 09:04:37.217674737 -0300
Modify: 2024-05-09 09:04:37.217674737 -0300
Change: 2024-05-09 09:04:37.217674737 -0300
 Birth: 2024-05-09 09:04:37.217674737 -0300

Tambien podemos verlo asi : sudo debugsfs -R "stat 25743601" /dev/sdb2

Inode: 25743601   Type: regular    Mode:  0664   Flags: 0x80000
Generation: 2630287901    Version: 0x00000000:00000001
User:  1000   Group:  1000   Project:     0   Size: 12
File ACL: 0
Links: 1   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x663cbbd5:33e5cfc4 -- Thu May  9 09:04:37 2024
 atime: 0x663cbbd5:33e5cfc4 -- Thu May  9 09:04:37 2024
 mtime: 0x663cbbd5:33e5cfc4 -- Thu May  9 09:04:37 2024
crtime: 0x663cbbd5:33e5cfc4 -- Thu May  9 09:04:37 2024
Size of extra inode fields: 32
Inode checksum: 0x25ec42f7
EXTENTS:
(0):49052144
  1. 25743601 es el numero de inodo
  2. /dev/sdb2 es el sistema de archivos

Los inodos son unicos por cada sistema de archivo, y podria repetirce en indice, es por eso que tenemos que indicar como ultimo parametro el sistema de arhivos.

Analicemos los datos retornados por el comando sudo debugsfs -R "stat 25743601" /dev/sdb2

  1. Inode: el numero de inodo xd
  2. Type: dice regular, porque es un fichero , si fuese un directorio diria directorio, si fuese un enlace simbolico, diria eso.
  3. Mode: Son los permisos
  4. Flags: determinan ciertas caracteristicas, como que este nodo referencia los bloques de disco donde esta almacendo el contenido. (“hola mundo”) utilizando un metodo que se donomina extension. De hecho podemos verlo en la ante ultima linea que dice EXTENDS.
  5. User: Nos dice quien es el propietario referenciado por un identificador.
  6. Group: El grupo por identificador. 7: Project: por default siempre es 0
  7. Size: El tamanio del fichero
  8. ACL: El control de acceso
  9. Links: El numero de encales duros. 11: Blockcount: numero de bloques que se reservaron para almacenado del archivo, 1 bloque puede llegar a tener un tamanio de 512bytes , por lo que nuestro arvhivo que pesa 29bytes nos esta ocupando 4096bytes. 12.Fragment: Nos da informacion de si nuestro archivo esta fragmentado, por ejemplo si tenemos un espacio en disco como el Swapfile que es de 2gb y el SO necesita alamcenar un arhivo, es dificil que justo tengamos disponible todo un segmento consecutivo donde guardalo junto, por eso lo que se hace es fragmentar el archivo en varios espacios de disco.
  10. Luego tenemos ctime que es cuando se creo, atime el ultimo acceso al archivo, mtime la ultima vez que el fichero fue modificado, crtime lo mismo que ctime
  11. Size of extra inode fields: Nos indica que tamanio a dicional tuvo que ocupar para guardar los datos.
  12. Inode checksum: Es la parte de un hash que sirve para validar la integridad de la informacion, que no de haya modificado por error entre otros.

Dentries

Si prestamos atencion en la informacion de debugs, el nombre del archivo no esta en ningun lado. Aca entran en juego las estructuras de directorios llamadas dentries (Directory entries) almacena unicamente , el inodo , el nombre de archivo y la longitud de su nombre.

A diferencian de los inodos de los fichereros que como dijimos antes : “Los inodos van referenciar los bloques dentro del disco donde se encuentra la infomacion del archivo” estos dentries no referencian los bloques dentro del disco, sino que el inodo de un directorio apunta a los inodos que estan dentro de el.

Las dentries mapean los nombres de los archivos y directorios a los inodos correspondientes. Cuando realizas operaciones de lectura, escritura o navegación en el sistema de archivos, el sistema operativo primero consulta las dentries para encontrar el inodo asociado con el archivo o directorio de interés.

Este enfoque proporciona una capa de indirección que facilita la búsqueda eficiente de archivos y directorios en el sistema de archivos, ya que el sistema operativo no necesita buscar directamente los inodos de todos los archivos y directorios. En cambio, puede buscar en la estructura de dentries para encontrar el inodo correcto más rápidamente.

Las dentries son una capa de abstracción que hace referencia a los inodos subyacentes en el sistema de archivos de Linux, y esta indirección facilita un acceso más eficiente a los archivos y directorios en el sistema de archivos.

Para verlo hacemo ls -lid /home/akerman

25690114 drwxr-x--- 39 akerman akerman 4096 May  9 10:20 /home/akerman

Podemos mas informacion con ls -lia /home/akerman como dato de colo si vemos el inodo de .. y hacemos stat "inode" veremos que es la ruta /home.

Los nodos no exiten en todos los sistemas de archivos, por ejemplo , lo nodos exiten en sitemas ext4 y en otros de linux, pero en windows usan otros, pero basicamente haran lo mismo.

Es una referencia a un directorio o fichero, es el equivalente a un acceso directo de windows, aunque los enalaces simbolicos son mucho mas antiguos.

Se ven en ls -l algo asi :

lrwxrwxrwx   1 root root          7 Apr 18  2023 bin -> usr/bin

Porque nos interesa tener este tipo de estructura en nuestro sistema

de ficheros?

  1. Razones de retro compatibilidad, hay software antiguo que hace uso por ejemplo del bin que esta en la raiz, hoy en dia este se entuenta en usr/bin. Si no tuvieramos ese bin estos programas no funcionarian.
  2. Podemos por ejemplo tener multiples versiones de un sofware. Por ejemplo tenemos Python 2 y Phiton 3 en nuestro sistema, pero queremos quen al usar python en la terminal , siempre ejecute pyton3 entonces hariamso algo asi :
ln -s /ruta/a/python3.9 /usr/local/bin/python

Si luego queremos que por default sea pyton2 hariamos :

ln -s /ruta/a/python2.x /usr/local/bin/python

La ruta /usr/local/bin/python es la ubicación en la que se encuentra un archivo ejecutable llamado python. En sistemas Unix y Linux, la carpeta /usr/local/bin es una ubicación común para almacenar programas y scripts que no forman parte de la distribución base del sistema operativo, sino que se instalan localmente por el usuario o administrador del sistema. Entonces, /usr/local/bin/python es un camino hacia un ejecutable de Python que probablemente haya sido instalado localmente en tu sistema. Esto podría ser una versión de Python que has compilado e instalado manualmente, o una versión que has instalado utilizando un gestor de paquetes como pip o conda. La convención es usar /usr/local para programas y scripts que no son parte del sistema operativo base, sino que son instalados por el usuario o administrador del sistema. Y /usr/local/bin es donde se colocan los ejecutables de esos programas y scripts para que estén disponibles en el PATH del usuario.

Que relacion tiene un enlace simbolico como se relacionan con los inodos?

Si hacemos ls -lid / veremos el enlace de bin -> usr/bin con su inode, este inode puede ser un numero cualquiera, digamos 23, entonces, como este esta linkeado a usr/bin podemos pensar que el inode de usr/bin es 23 , probemos lo siguiente : ls -lid /usr/bin veremos que es cualquier otro como puede ser 5438292.

Con esto ya podemos darnos cuenta que los Enlaces tienen sus propios inodo.

Veamos mas detalles con sudo debugfs -R "stat <13>" /dev/sdb2:

Inode: 13   Type: symlink    Mode:  0777   Flags: 0x0
Generation: 885356200    Version: 0x00000000:00000002
User:     0   Group:     0   Project:     0   Size: 7
File ACL: 0
Links: 1   Blockcount: 0
Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x659fde48:4329c5a4 -- Thu Jan 11 09:25:44 2024
 atime: 0x663b9429:bcc0ca90 -- Wed May  8 12:03:05 2024
 mtime: 0x643efe50:00000000 -- Tue Apr 18 17:32:16 2023
crtime: 0x659fde48:4329c5a4 -- Thu Jan 11 09:25:44 2024
Size of extra inode fields: 32
Inode checksum: 0xc1830be7
Fast link dest: "usr/bin"

Si vemos Blockcount aparentemente este enlace no contiene la informacion del fichero o directorio al que apunta. Entonces que tiene? solo el Fast link dest que es la referencia a usr/bin.

Si vemos el size, vemos que pesa 7bits que son los 7 caracteres de usr/bin.

En definitiva, tiene un inodo independiente pero no alamacena la informacion mas que el ficho o el directorio al que apunta.

Otro dato es que todos los enlaces comienzan en sus permisos con l de link

13 lrwxrwxrwx 1 root root 7 Apr 18  2023 /bin -> usr/bin

Como crear enlaces simbolico

ln -s Desktop/fichero-a-linkear nombre-de-simbolico el -s es de soft

Si eliminamos fichero-a-linkear y vemos con ls veremos que ahora el nombre-simbolico esta en rojo, porque esta roto, pero el link sigue existiendo.

Estos enlaces pueden crearce son rutas relativas file.txt o absolutas /home/akerman/Desktop/file.txt. El usar una u otra depende del contexto.

Si movemos el enlace a otro sistema de ficheros , nos conviene usar las absolutas, para que tenga toda la
ruta hacia el fichero.

Si lo que voy a mover es el directorio principal que contiene los enlaces como los otros directorios, entonces uso relativas.

Estos son anteriores los enlaces simbolicos, hoy en dia se recomienda usar los simbolicos.Pero veremos de que se trata y en que se diferencia.

Lo primero es que no se pueden aplicar a directorios, solo a ficheros.

Por otro lado para hacer un enlace duro usamos la misma utilidad que antes.Pero sin el flag -s

ln Desktop/fichero.txt enlace_duro

Si hacemos un ls veremos que enlace_duro aparece como un fichero normal no vemos el tipico -> que indique a que hace referencia. Ni nos indica en el apartado de permisos que ese un enlace con la primer letra en l.

El peso tampoco es le mismo, ya no pesa lo mismo que su longitud de nombre.

Como digimos antes, si haciamos ls -li podemos ver el numero de inodo, el cual en los soft links un numero era para el link y otro era para el archivo real, al que se le hacia referencia.

En este caso si hacemos ls -li Desktop/fichero.txt y vemos el inodo, esta vez coincide con el original.

Esto nos indica que es una referencia directa, por lo cual es como si fuera el arhivo original.

Por lo que, si eliminamos el fichero original, en vez de romper el enlace y verlo en rojo como pasaba con el soft link , ahora tambien podemos ver la infomacion original.

Esto es asi porque el hard link sigue apuntando al inodo que conoce el espacio en disco donde esta esa informacion.

Podemos crear muchos enlaces duros sobre el mismo fichero, como podemos saber cuantos links tienen un fichero?

Si hacemos ls -l veremos que despues de los permisos tenemos un numero, estos nos dicen la cantidad de enlaces duros al que estan apuntando a ese fichero o inodo.

drwxr-xr-x 1 akerman akerman  32 May  4 13:59 Documents/
drwxr-xr-x 1 akerman akerman  64 May  5 11:38 Downloads/

Como ultimo dato, si hacemos una carpeta con mkdir test y listamos con ls -l veremos que por default tiene 2 hard links. Pero nosotros solo creamos uno, donde esta ese hard link?, si entramos con cd test y hacemos ls -la veremos que es .

Wildcards

Son comodines que nos ayudan a ser mas eficientes, por ejemplo , creemos dos archios:

touch text1.txt texto2.txt

Y en cada uno escribimos un relleno, al momento de leerlos por terminal podemos hacer cat text1.txt text2.txt.

Si tuvieramos mas,haceer esto es poco eficaz, asi que el primer wildcard que veremos sera * que significa, cualquer caracter o cualquier numero de caracteres. cat fichero*

Otro ejemplo con ls seria ls D* esto nos lista todos los directorios que comienzan con D junto con sus subfiles. Con ls -d D* veremos solo losn resultados del directorio actual.

Tenemos a disposicion el simbolo ? que significa cualquier caracter pero uno solo

Para sacar text1.txt texto2.txt tendria que hacer cat fichero?.txt

Podemos indicar tambien una lista de caracteres con [] , entonces lo usariamos asi : cat fichero[1234].txt esto le indica que queremos que nos devuelva el contenido de cualquier fichero que contenga 1,2,3 o 4

Tambien podemos usar la negacion con ! asi: file[!1234].txt asi, nos traera todos los que no empiecen ni con 1,2,3 o 4

El comodin [[:class:]] nos permite poner una clase por ejemplo, si queremos que sean numeros en vez de ponerlos a mano como haciamos antes hariamos: cat fichero[[:digit:]].txt

Otras opciones serian alpha, alnum , upper,lower

Ejemplo :

ls -d [[:upper:]]*

Esto nos devolvera cualquier directorio que comience con Mayuscula en el directorio actual.

Podemos combinar por ejemplo cat fichero[![:digit:]] asi nos saca a pantalla todos los ficheros que no contentan digitos.

Shell Expansion

Cuando usamos los wildcard y usamos por ejemplo ls fichero* lo que hace la shell es expandir.

El concepto de expansion va mas alla que las wildcards.

El comando echo

Este comando mostrara por pantalla cualquier texto que le pasemos por argumento.Ej:

echo esto es una prueba

esto es una prueba

Lo que hace realmente es redirigir el texto a lo que se donomina standard output.

Expensiones

Cuando usamos echo y hacemos echo fichero* lo primero que hace es sustituir por los caracteres necesarios yu luego los enviar al standard output.

echo fichero*

fichero1.txt fichero2.txt

Seria lo mismo que haberlo hecho a mano echo fichero1.txt fichero2.txt

Recordemos que si usamos ~ en realidad referencia a nuestro directorio de trabajo del usuario actual (/home) veamos como extande el caracter la shell:

echo ~

/home/akerman

Podemos aplicar el concepto de expansion en las rutas , si hacemso

echo *

proyectos/ pruebas/ text1.txt text2.txt

Demos un uso mas copado, como hacemos si queremos expandir aquellos directorios que tengan como subdirectorios un folder logs?

echo /*/log

/dev/log /run/log /var/log

Basicamente lo que estamos dicienod es que desde la raiz / cualquier carpeta * que contenga log

Podes hacer estas pruebas con ls, pero con echo es mas limpio

Operaciones

La shell nos permite no solo usar ese tipo de comodin, sino que tambien podemos usar operaciones aritmeticas.

Suma

echo $((2+2))
4

Podemos hacer todo tipo de operaciones.

Resta

echo $((2-2))
0

Potencia

echo $((2**1))
2

Podemos combinar con ficheros asi : cat fichero$((1+1)).txt y mostrara el contenido de fichero2.txt ya que expandio $((1+1))

Brace expansion

Estas expansiones funcionan de la siguiente forma:

echo {1,2,3}

1 2 3

La onda es usarlo junto a texto:

echo fichero{1,2,3}.txt

fichero1.txt fichero2.txt fichero3.txt

Como vemos repite el texto con cada uno de los caracteres que pusimos entre llaves.

Nos sirve para optimizar la creacion de directorios y ficheros de la siguiente manera:

echo fichero{1...100}

fichero1.txt fichero2.txt fichero3.txt fichero4.txt fichero5.txt
fichero6.txt fichero7.txt fichero8.txt fichero9.txt fichero10.txt
fichero11.txt fichero12.txt fichero13.txt fichero14.txt fichero15.txt
fichero16.txt fichero17.txt fichero18.txt fichero19.txt fichero20.txt 
fichero21.txt fichero22.txt fichero23.txt fichero24.txt fichero25.txt
fichero26.txt fichero27.txt fichero28.txt fichero29.txt fichero30.txt
fichero31.txt fichero32.txt fichero33.txt fichero34.txt fichero35.txt
fichero36.txt fichero37.txt fichero38.txt fichero39.txt fichero40.txt
fichero41.txt fichero42.txt fichero43.txt fichero44.txt fichero45.txt
fichero46.txt fichero47.txt fichero48.txt fichero49.txt fichero50.txt
fichero51.txt fichero52.txt fichero53.txt fichero54.txt fichero55.txt
fichero56.txt fichero57.txt fichero58.txt fichero59.txt fichero60.txt
fichero61.txt fichero62.txt fichero63.txt fichero64.txt fichero65.txt
fichero66.txt fichero67.txt fichero68.txt fichero69.txt fichero70.txt
fichero71.txt fichero72.txt fichero73.txt fichero74.txt fichero75.txt
fichero76.txt fichero77.txt fichero78.txt fichero79.txt fichero80.txt
fichero81.txt fichero82.txt fichero83.txt fichero84.txt fichero85.txt
fichero86.txt fichero87.txt fichero88.txt fichero89.txt fichero90.txt
fichero91.txt fichero92.txt fichero93.txt fichero94.txt fichero95.txt
fichero96.txt fichero97.txt fichero98.txt fichero99.txt fichero100.txt

Podriamos haber usado mkdir y funcionaria

Incluso podemos usar letras :

echo {A..Z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Podemos tambien anidarlas:

echo texto{A{1,2},B{3,4}}final

textoA1final textoA2final textoB3final textoB4final

Por ejemplo podemos armar directorios de los por anio y mes :

mkdir {2020..2024}-{01..12}

2020-01  2020-06  2020-11  2021-04  2021-09  2022-02  2022-07  2022-12  2023-05  2023-10  2024-03  2024-08
2020-02  2020-07  2020-12  2021-05  2021-10  2022-03  2022-08  2023-01  2023-06  2023-11  2024-04  2024-09
2020-03  2020-08  2021-01  2021-06  2021-11  2022-04  2022-09  2023-02  2023-07  2023-12  2024-05  2024-10
2020-04  2020-09  2021-02  2021-07  2021-12  2022-05  2022-10  2023-03  2023-08  2024-01  2024-06  2024-11
2020-05  2020-10  2021-03  2021-08  2022-01  2022-06  2022-11  2023-04  2023-09  2024-02  2024-07  2024-12

Command Substitution

Una de las tantas maneras que tenemso para saber la ruta de un programa es con which si hacemos which cat veremos la salida /usr/bin/cat

Bien, ahora supongamos que queremos listar los permisos de ese directorio, podriamos intentar los siguiente:

ls -la which cat

Pero eso nos devuelve el error de que no concuentra which, ya que lo esta considerendo un argumento.

Nosotros lo que necesitamos es que tome el resultado de which cat como argumento. Ahi es donde estra la funcionalidad substitution.

ls -la $(which cat)

-rwxr-xr-x 1 root root 34992 Mar 28 19:09 /usr/bin/cat

Si hacemos la prueba con python3 :

python3 -c 'print("hola mundo")'

hola mundo 

Vemos que imprime por consola el print esto tambien podemos mezclarlo con command Substitution.

echo $(python3 -c 'print("hola mundo")')

hola mundo

Tene en cuenta que en versiones antiguas de bash para hacer comand Substitution se usa “ hay retro compatibilidad por lo que si hacemos ls -la which cat funciona.Lo recomendado es usar $() porque es lo mas nuevo.

Comillas en la shell de Linux

Cuando usamos comillas dobles __” ” __ todos los caracteres especiales a exepcion de 3, perderan su significado.

Esos caracteres que mantienen su significado son :

  1. $
  2. \
  3. `

Entonces si hacemos echo "fichero*" no devolvera nada , porque * ya no es un comodin, pero si hacemos :

echo "la ruta de cat es : $(which cat)"

la ruta de cat es /usr/bin/cat

Ademas las dobles comillas nos permite que la shell respete los espacios :

echo esto tiene            espacio

esto tiene espacio 
echo "esto tiene            espacio"

esto tiene                espacio 

Basicamente logramos que los simbolos que hacen una expansion, no se interpreten como {} [] {1..100} y asi saldran literalmente como los escribimos.

Una cosa tener en cuenta con las dobles comillas son las siguiente:

echo $(ls)

delete proyectos pruebas text1.txt text2.txt

Como vemos si hubiera espacios adicionales o saltos de lina, tabulaciones ,etc echo los omite, ya que expande los resultados y luego los pasa como argumento a echo y posteriormente imprime en pantall.

Pero recordemos que las comillas dobles respetan todos eso saltos de linea.

echo "$(ls)"

delete
proyectos
pruebas
text1.txt
text2.txt

Es importante tener en cuenta que aunque usemos los mismos comandos y funcionen el resutado puede variar en estos saltos de linea.

Comillas simples

Las simples omiten el comportamiento especial de todos los caractres como :

  1. $
  2. \
  3. `

Por lo que :

echo "la ruta de cat es : $(which cat)"

la ruta de cat es $(which cat)

Escapando caracteres especiales

Si estamos usando comillas dobles y queremos que de manera selectiva algunos caractres especiales se interpereten y otros no , tenemos que usar \ de la siguiente manera.

echo "esto es una expansion $(which cat), y esto no \$(which cat)"

esto es una expansion /usr/bin/cat, y esto no $(which cat)

Otra utilidad de \ es cuando tenemos un fichero con espacios onda 'fichero espacio.txt' y queremos hacer un ls -la lo usariamos asi : ls -la fichero\ espacio.txt

Codigos de control

Si queremos que echo interpete ciertos codigos que se usan on \ tnemos que usar el flag -e

echo -e "\a"

Al dar enter escucharemos un pitido.

echo -e "este texto \t tiene tabulacion"

este texto 	tiene tabulacion
echo -e "este texto \n tiene nueva linea"

este texto
tiene nueva linea