Quelques bonnes pratiques…#

Évitez les espaces !#

Vous remarquerez que les fichiers et dossiers sous Linux ne contiennent généralement pas d’espaces. Il sont remplacés par un tiret bas : _

Bien qu’il soit possible d’utiliser des espaces dans les noms de fichiers/dossiers, cette pratique risque de d’engendrer des erreurs !

Voyons ça d’un peu plus près…

Vous connaissez la syntaxe générique des commandes linux:

command [options] argument1 argument2

Ici, les arguments sont séparés par des espaces. Si vous essayez d’utiliser directement des noms de fichiers avec des espaces, ils seront traités comme des arguments distincts plutôt que comme un seul argument.

Exemple - on veut écrire le texte “bonjour EBAII 2023” dans le fichier : bonjour ebaii.txt

echo "bonjour EBAII 2023" > bonjour ebaii.txt
cat bonjour ebaii.txt
bonjour EBAII 2023 ebaii.txt
cat: ebaii.txt: No such file or directory
?2004h

on obtient une erreur ! Linux ne comprend pas que bonjour ebaii.txt est un seul argument. Il traite bonjour et ebaii.txt séparément.

Quand on regarde le contenu du fichier bonjour qui a été créé, on comprend comment notre commande a été traitée par le système.

$ cat bonjour
bonjour EBAII 2023 ebaii.txt

Alors, comment gérer les espaces dans les noms de fichiers/dossiers ? Vous avez 2 possibilités:

  1. Enveloppez le nom complet du fichier entre guillemets : "bonjour ebaii.txt"

  2. Échapper chaque espace à l’aide du caractère barre oblique inverse : bonjour\ ebaii.txt

echo "bonjour EBAII 2023" > "bonjour ebaii.txt"
cat "bonjour ebaii.txt"
bonjour EBAII 2023
echo "bonjour EBAII 2023" > bonjour\ ebaii.txt
cat bonjour\ ebaii.txt
bonjour EBAII 2023

C’est utile, mais pas très lisible : Exemple pour un chemin /home/user/mon\ dossier\ de\ projet/experience\ jour \ 1/fichier\ resultats.csv

CONCLUSION : Pour vous éviter de gros soucis et aussi ne pas froisser les bioinformaticiens les plus suceptibles, il faut éviter d’utiliser les espaces dans vos noms de fichiers/dossier et de les remplacer par le tiret bas: _

Attention aux fichiers provenant de Windows/MacOS#

Bien que Linux soit un sytème complet, performant, permettant de réaliser tous les traitements de fichiers, vous aurez surement besoin d’importer un fichier (référence, fichier texte, script) provenant de Windows ou MacOS.

Cet acte aussi anodin qu’on pourrait le croire peut vous conduire à une succession d’erreurs difficiles à identifier, mais finalement tellement simples à résoudre en amont.

Imaginons que vous souhaitiez écrire un nouveau script bash pour tester vos nouvelles compétences. Un simple script de quelques lignes…

Mais en voyant le travail collosale pour maitriser un éditeur de texte sous Linux (pourtant c’est super simple !! si si !!), vous vous dites qu’après tout je vais éditer mon script dans mon traitement de texte favoris, puis je l’enregistrerai au format texte pour le télécharger ensuite dans le dossier home du cluster de calcul.

Chargeons le script suivant, donnons lui les droits d’éxécution avec la commande chmod +x et affichons le contenu du script:

wget https://raw.githubusercontent.com/IFB-ElixirFr/LinuxEBAII/EBAII23/docs/data/my_script_windows.sh
chmod +x my_script_windows.sh
cat my_script_windows.sh
--2023-11-04 12:47:49--  https://raw.githubusercontent.com/IFB-ElixirFr/LinuxEBAII/EBAII23/docs/data/my_script_windows.sh
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 141 [text/plain]
Saving to: ‘my_script_windows.sh’

100%[======================================>] 141         --.-K/s   in 0s      

2023-11-04 12:47:49 (7.58 MB/s) - ‘my_script_windows.sh’ saved [141/141]

#!/bin/bash
#Ecrit hostname dans une variable
host_name=$(hostname)
#Affiche hostname avec la commande echo
echo "hostname: $host_name"

La commande cat affiche les lignes suivantes essayons de comprendre rapidement ce que fait notre script :

#!/bin/bash
#Ecrit hostname dans une variable
host_name=$(hostname)
#Affiche hostname avec la commande echo
echo "hostname: $host_name"

Jusqu’ici tout va bien… On va executer notre script:

./my_script_windows.sh
bash: ./my_script_windows.sh: /bin/bash^M: bad interpreter: No such file or directory

Le shell vous retourne une erreur : "/bin/bash^M : mauvais interpréteur: Aucun fichier ou dossier de ce type" ?????

Pourtant le script semble bien écrit ? Alors il faut aller chercher plus loin…

Dans un fichier texte, plusieurs conventions incompatibles existent pour représenter la fin de ligne ou la fin de paragraphe. Les trois conventions principales trouvent leur origine dans des systèmes d’exploitation concurrents:

  1. Dans la convention « Unix » (Linux), la fin de ligne est indiquée par le caractère saut de ligne (LF - Line Feed, code 10 de la table ASCII).

  2. Dans la convention « Mac », la fin de ligne est indiquée par le caractère retour chariot (CR - Carriage Return , code 13 de la table ASCII).

  3. Dans la convention « DOS » (Windows), la fin de ligne est indiquée par la combinaison des deux caractères CR puis LF.

On va regarder le fichier un peu plus en détail avec la commande:

cat -A my_script_windows.sh
#!/bin/bash^M$
#Ecrit hostname dans une variable^M$
host_name=$(hostname)^M$
#Affiche hostname avec la commande echo^M$
echo "hostname: $host_name"^M$

Les lignes suivantes s’affichent :

#!/bin/bash^M$
#Ecrit hostname dans une variable^M$
host_name=$(hostname)^M$
#Affiche hostname avec la commande echo^M$
echo "hostname: $host_name"^M$

Les caractères ^M en fin de ligne apparaissent lorsque vous créez un fichier texte sur Windows et que vous transférez le fichier sur Linux par exemple avec SCP ou FTP. Ils correspondent au retour chariot de fichier sur DOS.

En effet, comme vu plus haut, le retour chariot est différent dans le monde Linux et le monde Windows.

On va utiliser la commande File afin d’obtenir des informations sur le type de fichier. C’est une commande utile lorsque l’on tombe sur un fichier inconnu ou que l’on a des doutes quant au type de fichier.:

file my_script_windows.sh
my_script_windows.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
my_script_windows.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

Et oui le fichier n’est pas au bon format : with CRLF line terminators ==> il s’agit d’un fichier de type “DOS” probablement édité dans Windows

Pour éviter tout problème futur, on va convertir notre fichier au bon format avec la commande dos2unix - DOS/MAC to UNIX text file format converter

dos2unix my_script_windows.sh
file my_script_windows.sh
dos2unix: converting file my_script_windows.sh to Unix format ...
my_script_windows.sh: Bourne-Again shell script, ASCII text executable
my_script_windows.sh: Bourne-Again shell script, ASCII text executable

Cette fois on a bien un fichier au format texte, compatible Linux

cat -A my_script_windows.sh
./my_script_windows.sh
#!/bin/bash$
#Ecrit hostname dans une variable$
host_name=$(hostname)$
#Affiche hostname avec la commande echo$
echo "hostname: $host_name"$
hostname: cpu-node-41.ifb.local

CONCLUSION : ici nous avons vu l’exemple d’un script, mais ce pourrait être un fichier fasta, un fichier d’annotation, etc… La règle à appliquer est la suivante : dès que vous importez un fichier qui a été créé ou modifié dans un autre système d’exploitation (Windows, MacOS), vérifier bien le type de fichier avec la commande File.

Si besoin, utilisez la commande dos2unix pour le convertir et ainsi éviter de potentiels erreurs difficiles à identifier !