top of page

Réduire en automatique la taille d'une image disque de carte SD de Raspberry Pi

  • Photo du rédacteur: Jacques Tenneguin
    Jacques Tenneguin
  • 14 mars
  • 5 min de lecture

Dernière mise à jour : 2 avr.

Réduire en automatique la taille d'une image disque de carte SD de Raspberry Pi grâce à un script bash (_shrink_sd_card.sh)


Pour ce faire, vous devez, dans un premier temps, réaliser une copie de votre carte SD de Raspberry Pi sur votre disque PC. Reportez vous au blog sur la création d’une image disque de Raspberry Pi.


Puis lorsque votre image de Raspberry Pi est placée sur le disque de votre PC, lancez l’utilitaire écrit en Bourne Bash avec la commande suivante :

$ . ~/_shrink_sd_card.sh NomDeFichierImageACompresser


Le fichier script _shrink_sd_card.sh doit être placé sous la racine du système. Sinon placez le dans un répertoire et appelez le script en mettant ce nom de répertoire avant le nom du script comme :

$ . ~/Documents/_shrink_sd_card.sh NomDeFichierImageACompresser

si vous avez copié le script dans ~/Documents/


Voici les écrans affichés lors d’un déroulement standard :


Voici les premières lignes de l'exécution du script
Voici les premières lignes de l'exécution du script

Le script analyse la structure de l'image et corrige si nécessaire cette dernière.
Le script analyse la structure de l'image et corrige si nécessaire cette dernière.

En arrivant vers la fin, les messages en rouge ne sont pas des erreurs définitives.
En arrivant vers la fin, les messages en rouge ne sont pas des erreurs définitives.

Le script arrive enfin à son terme (plusieurs dizaines de minutes sont nécessaires).
Le script arrive enfin à son terme (plusieurs dizaines de minutes sont nécessaires).

Voici enfin le script qui a servit à l'affichage des écrans précédents :

#!/bin/bash
# _shrink_sd_card.sh
# Script Initial par Jésus Forain :
# https://www.jesus-forain.fr/blog/reduire-la-taille-d-une-image-de-carte-sd-d-un-raspberry-pi-136.html
# Modifications par Jacques Tenneguin
# https://axiomeinfo21.com

_fErr()
{
	if [ "$LOOP" == "true" ]; then
		sudo losetup -d /dev/loop$loopNb
	fi
}

# Définition des paramètres en Français et Anglais
FR=0
GB=1
aUNITS=( "Unités" "Units" )
aBLOCKCOUNT=( "Nombre blocs" "Block count" )
aBLOCKSIZE=( "Taille bloc" "Block size" )
LOOP="false"

#
# Fichier image
#
# Vérification des arguments
if [ -z "$1" ]; then
	echo
	echo "[ERREUR] Indiquer en paramètre le fichier image à redimentionner"
	echo
	return 1
fi

imageFile="$1"

#
# Demande de confirmation
#
echo "ATTENTION! ce script est fait pour redimentionner les images de cartes SD de Raspberry Pi utilisant Raspberry Pi OS. L'utilisation de ce script pour un autre utilisation risque de produire des résultats inattendus. Les structures issues de NOOBS_x_x_x.zip ne sont pas gérées par ce script."

echo "Pour plus de détails et l'explication du script, voir ici: https://www.jesus-forain.fr/blog/reduire-la-taille-d-une-image-de-carte-sd-d-un-raspberry-pi-136.html ou https://axiomeinfo21.com"
echo

echo "Le fichier image donné en argument sera modifié, il est conseillé de faire une copie de sauvegarde de ce fichier image"
echo

echo "Fichier à réduire: $imageFile"
read -p "Confirmer (O/N)? " confirm

if [ $confirm != "o" ] && [ $confirm != "O" ]; then
	return 0
fi
echo

#
# Verification du nombre de partitions de l'image
#
declare -i _Nb=0; let _Nb=$( sudo fdisk -l "$imageFile" | grep -c "$imageFile" ); let _Nb--
if [ $_Nb -ne 2 ]; then
	echo "[ERREUR] échec l'image ne contient pas 2 partitions"
	return 2
fi

echo "[INFO] L'image contient bien 2 partitions seulement"
echo

#
# Recherche d'un périphérique loop libre
#
echo "[INFO] Recherche d'un périphérique /dev/loopX libre"
loopNb=0
nbLoopDevices=$(ls -l /dev | grep -e "loop[0-9]\+" | wc -l)
echo -e "$nbLoopDevices périphériques /dev/loopX disponibles"
sudo losetup | grep /dev/loop$loopNb > /dev/null
while (( $? == 0 )); do
	echo "/dev/loop$loopNb est utilisé"
	loopNb=$(($loopNb + 1))

	# Plus de loopX disponible
	if (($loopNb >= $nbLoopDevices)); then
		echo "[ERREUR] aucun périphérique /dev/loopX libre"
		return 3
	fi

	sudo losetup | grep /dev/loop$loopNb > /dev/null
done

LOOP="true"
echo "[INFO] /dev/loop$loopNb est libre"
echo

#
# Montage de l'image
#
echo "[INFO] Montage de l'image"
sudo losetup /dev/loop$loopNb "$imageFile"

if (( $? != 0 )); then
	echo "[ERREUR] échec du montage de l'image"
	_fErr; return 4
fi
echo

#
# Rechargement de la table des partitions
#
echo "[INFO] Rechargement de la table des partitions"
sudo partprobe /dev/loop$loopNb
if (( $? != 0 )); then
	echo "[ERREUR] échec du rechargement de la table des partitions"
	_fErr; return 5
fi
echo

# Affichage de la structure des partitions
echo "[INFO] affichage de la structure des partitions"
sudo lsblk /dev/loop$loopNb
echo

#
# Vérification du filesystem
#
echo "[INFO] Vérification du filesystem"
sudo e2fsck -y -f /dev/loop${loopNb}p2

# Pas de vérifications du code retour car s'il y a des corrections la valeur est "faux"
echo

#
# Redimensionnement du filesystem
#
echo "[INFO] Redimensionnement du filesystem. Cette étape est la plus longue du script et peut durer plusieurs dizaines de minutes selon la taille du fichier image"
sudo resize2fs -p /dev/loop${loopNb}p2 -M
if (( $? != 0 )); then
	echo "[ERREUR] échec du redimensionnement du filesystem"
	_fErr; return 6
fi
echo

# Récupération d'informations sur les partitions
echo "[INFO] Récupération d'informations sur les partitions"
blockCount=$(sudo dumpe2fs -h /dev/loop${loopNb}p2 2>/dev/null | grep "${aBLOCKCOUNT[$FR]}" | awk '{print $3}')

if [ "$blockCount" == "" ]; then
	blockCount=$(sudo dumpe2fs -h /dev/loop${loopNb}p2 2>/dev/null | grep "${aBLOCKCOUNT[$GB]}" | awk '{print $3}')
fi

blockSize=$(sudo dumpe2fs -h /dev/loop${loopNb}p2 2>/dev/null | grep "${aBLOCKSIZE[$FR]}" | awk '{print $3}')
if [ "$blockSize" == "" ]; then
	blockSize=$(sudo dumpe2fs -h /dev/loop${loopNb}p2 2>/dev/null | grep "${aBLOCKSIZE[$GB]}" | awk '{print $3}')
fi

sectorsUnits=$(sudo fdisk -l "$imageFile" | grep "${aUNITS[$FR]}" | awk '{print $4}')

if [ "$sectorsUnits" == "" ]; then
	sectorsUnits=$(sudo fdisk -l "$imageFile" | grep "${aUNITS[$GB]}" | awk '{print $4}')
fi

sectorsBaseSize=$(sudo fdisk -l "$imageFile" | grep "${aUNITS[$FR]}" | awk '{print $6}')
if [ "$sectorsBaseSize" == "" ]; then
	sectorsBaseSize=$(sudo fdisk -l "$imageFile" | grep "${aUNITS[$GB]}" | awk '{print $6}')
fi

sectorsSize=$(($sectorsUnits * $sectorsBaseSize))

partitionStart=$(sudo fdisk -l /dev/loop$loopNb | grep -e "/dev/loop${loopNb}p2.*Linux" | awk '{print $2}')
if [ "$partitionStart" == "" ]; then
	# Au cas ou la 2me partition n'est de type linux
	partitionStart=$(sudo fdisk -l /dev/loop$loopNb | grep -e "/dev/loop${loopNb}p2.*" | awk '{print $2}')
fi
partitionEnd=$((($blockCount * $blockSize) / $sectorsSize + 1))
echo

echo "[INFO] Informations sur les partitions"
echo "nombre de blocs : $blockCount"
echo "taille de bloc : $blockSize octets"
echo "taille de secteur : $sectorsSize octets"
echo "début de partition: $partitionStart"
echo "fin de partition : ($blockCount * $blockSize) / $sectorsSize + 1) = $partitionEnd"

if [ "$blockCount" == "" ] || [ "$blockSize" == "" ] || [ "$sectorsUnits" == "" ] || \
[ "$sectorsBaseSize" == "" ] || [ "$sectorsSize" == "" ] || [ "$partitionStart" == "" ] || \
[ "$partitionEnd" == "" ]; then
	echo "[ERREUR] Vérifiez les langues de sudo fdisk et sudo dumpe2fs : Anglais ou Français : UNITS, BLOCKCOUNT, BLOCKSIZE, ..."
	_fErr; return 7
fi
echo

#
# Modification des partitions
#
echo "[INFO] Modification des partitions"

# Script sudo fdisk trouvé ici:
# https://superuser.com/questions/332252/how-to-create-and-format-a-partition-using-a-bash-script
sed -e 's/\s*\([\+0-9a-zA-Z]*\).*/\1/' << EOF | sudo fdisk /dev/loop$loopNb
p # afficher la table des partitions
d # menu supprimer la partition
2 # supprimer la partition N°2
n # menu nouvelle partition
p # type de partition (primaire)
2 # appliquer à la partition N°2
$partitionStart # début de la partition
+$partitionEnd # fin de la partition. Attention, il y a un '+' devant la taille
# Do you want to remove the signature? [Y]es/[N]o: => non par défaut
p # affichage du nouveau partitionnement
w # écriture des modifications sur les partitions
q # Quitter
EOF

# Pas de vérification de la valeur de retour car ça sera toujours faux à cause du message "Re-reading the partition table failed.: Argument invalide"
# Récupération d'infos sur la nouvelle partition
newPartitionEnd=$(sudo fdisk -l /dev/loop$loopNb | grep -e "/dev/loop${loopNb}p2.*Linux" | awk '{print $3}')
newFileSize=$((($newPartitionEnd + 1) * $sectorsSize))

if [ "$newPartitionEnd" == "" ] || [ "$newFileSize" == "" ]; then
	echo "[ERREUR] Vérifiez les partitions de sudo fdisk..."
	_fErr; return 8
fi
echo

#
# Redimentionnement du fichier image
#
# Détacher la disque virtuel /dev/loopX
echo "[INFO] Détacher le disque virtuel /dev/loop$loopNb"
sudo losetup -d /dev/loop$loopNb

if (( $? != 0 )); then
	echo "[ERREUR] échec du détachement du périphérique /dev/loop$loopNb"
	_fErr; return 9
fi
echo

# Réduction du fichier image
echo "[INFO] Réduction du fichier image à $newFileSize octets"
sudo truncate -s $newFileSize "$imageFile"

if (( $? != 0 )); then
	echo "[ERREUR] échec de la réduction du fichier image"
	_fErr; return 10
fi
echo

echo "Ok : Réduction du fichier image terminée"
echo

Comments


Nous contacter

Entité de Dijon
Entité de Tournus - Sennecey le Grand

© 2019-2025

par AXIOME Informatique 21

& Wix

bottom of page