Repository: qrti/shrink
Branch: master
Commit: 4f4cf14d3e28
Files: 8
Total size: 46.1 KB
Directory structure:
gitextract_ilp038ff/
├── .gitattributes
├── README.md
├── deprecated/
│ ├── readme_071.md
│ ├── readme_081.md
│ ├── shrink_071.sh
│ ├── shrink_081.sh
│ └── shrink_092.sh
└── script/
└── shrink.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
================================================
FILE: README.md
================================================
# **shrink**
**Linux bash script to resize Raspberry SD card images**
consider further [remarks](#remarks)
### **new version**
\- dependency tests
\- low memory warning
\- argument handling and help screen
\- automated size retrieving from GParted
\- progress bars with ETA for all time consuming actions
\- environment variable support
---
### **download**
download repository from GitHub,
unzip and copy for example to: ~/shrink
**or**
copy script to current directory
`wget https://raw.github.com/qrti/shrink/master/script/shrink.sh`
**or**
check if git is installed
`$ git --version`
if git is not installed
`$ sudo apt-get install git-all`
clone shrink repository to current directory
`$ git clone https://github.com/qrti/shrink.git`
---
### **necessary installs**
`$ sudo apt-get install gparted`
`$ sudo apt-get install pv`
---
### **prepare**
**before executing the script the first time, insert your SD card**
enter the following at the command line and find the name of your SD device and partitions
`$ df -h`
now extract the device name
example 1 for list entries like:
/dev/sdb1 + /dev/sdb2
omit digit at the end
result:
/dev/sdb
example 2 for list entries like:
/dev/mmcblk1p1 + /dev/mmcblk1p2
omit p and digit at the end
result:
/dev/mmcblk1
**make script executable once**
change directory
`$ cd ~/shrink/script`
`$ chmod 755 shrink.sh`
**or**
`$ chmod a+x shrink.sh`
---
### **execute**
**usage and help**
```
Usage:
(sudo) shrink.sh [<arguments>]
(sudo) shrink.sh -h | --help
(sudo) shrink.sh
```
examples:
`$ sudo ./shrink.sh`
read, resize and zero fill image
`$ sudo ./shrink.sh --compress --skip-fill`
read, resize and compress image without zero fill
`$ sudo ./shrink.sh --device /dev/mmcblk1`
read, resize and zero fill image from device /dev/mmcblk1
the help screen shows options and their current default values
```
Options:
-h --help show this screen
--user specify user who should own output files (default: root)
--device source and target SD card device (default: /dev/sdb)
--date_name image name, alternative with date and time: "image_191003113547 (default: image)"
--image image name with extension (default: image.img)
--details gparted details file path and name (default: ~/gparted_details.htm)
--compress compress new image (an extra file is generated) (default: false)
--write write new image to SD card (default: false)
--skip-read read image from SD card (false for an already existing image) (default: true)
--skip-resize resize image with GParted (default: true)
--skip-fill fill empty space of new image with zeroes, only possible if RESIZE=true (default: true)
```
**changing default values by editing the script**
`$ nano shrink.sh`
example for:
/dev/sdb1 + /dev/sdb2
omit digit
```
DEVICE=${DEVICE:-/dev/sdb}
```
example for:
/dev/mmcblk1p1 + /dev/mmcblk1p2
omit p and digit at the end
```
DEVICE=${DEVICE:-/dev/mmcblk1}
```
your username is filled in automatically, to override edit USER
```
USER=${USER:-`whoami`}
```
**changing default values by using environment variables**
default values can be overridden by passing them as env vars
for example to set DEVICE and READ enter at the command line
`$ sudo DEVICE=/dev/sdb READ=false ./shrink.sh`
explore the top of the script to configure some more things
---
### **remarks**
\- use this script completely at your own risk
be sure to have backups of your data
\- new versions not widely tested yet
look for previous versions in directory 'deprecated'
\- runs on physical or virtual Linux desktop systems
\- cannot handle Raspberry NOOBS images
\- do not shrink images to minimum
otherwise they won't start on your Raspberry
especially Raspbian Full *Desktop* images need some extra space, about >= 250 MB are advised
Raspbian *Lite* images might be more moderate
\- when starting from a shrinked SD card for the first time
expand the filesystem to fill its space
by raspi-config
`sudo raspi-config` -> *Expand Filesystem*
`sudo reboot`
**or**
from command line
`sudo raspi-config --expand-rootfs`
`sudo reboot`
\- the script is 'half automatic'
meaning at one point it will start GParted on desktop and guide you what to do
\- progress display of 'fill empty space' may not end at 100 % exactly
because of difficult file system overhead calculation
nevertheless space will be filled correctly
\- the script was developed and tested on a VirtualBox Windows host with Linux Mint guest
\- inspired by
[http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php](http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php)
Donations are welcome!
[](https://www.paypal.com/donate?business=qrt@qland.de¤cy_code=USD&amount=5.00)
---
### history
V0.5
initial version, script keel fix by Barleyman
V0.6
mmcblk naming support
V0.7
simplifications
V0.71
adaption for parted 3.2, p -> print
V0.8
automated size retrieving from GParted
progress bars with ETA for all time consuming actions
V0.81
default value override by environment variables
thanks to Leon Miller-Out
V0.9
argument handling and help screen
thanks to Pedro Figueiredo e Silva
V0.91
low memory warning
gparted details path hint
V0.92
dependency tests
thanks to Tom Troyer
V0.93
correction for chown warning
- - -
### copyright
shrink is published under the terms of ISC license
Copyright (c) 2025 [qrt@qland.de](mailto:qrt@qland.de)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================
FILE: deprecated/readme_071.md
================================================
# shrink V0.71
there is also a [newer version](README.md)
#### Linux bash script to resize Raspberry SD card images
consider further [remarks](#remarks)
#### download
download repository from GitHub,
unzip and copy for example to: ~/shrink
**or**
copy script to current directory
`wget https://raw.github.com/qrti/shrink/master/script/shrink_071.sh`
**or**
check if git is installed
`$ git --version`
if git is not installed
`$ sudo apt-get install git-all`
clone shrink repository to current directory
`$ git clone https://github.com/qrti/shrink.git`
- - -
#### necessary installs
`$ sudo apt-get install gparted`
`$ sudo apt-get install dcfldd`
- - -
#### configure
before executing the script the first time, insert your SD card
enter the following at the command line and find the name of your SD device and partitions
`$ df -h`
edit the script and enter your data between the quotation marks
`$ nano shrink_071.sh`
example for /dev/sdd1 + 2 (omit digit)
```
DEVICE="/dev/sdd"
```
example for /dev/mmcblk0p1 + 2 (omit px)
```
DEVICE="/dev/mmcblk0"
```
fill in your Linux user name at USER
```
USER="your user name"
```
explore the top of the script to configure some more things
- - -
#### execute
change directory
`$ cd ~/shrink`
make script executable once
`$ chmod 755 shrink_071.sh`
**or**
`$ chmod a+x shrink_071.sh`
execute script
`$ sudo ./shrink_071.sh`
- - -
#### remarks
\- use this script completely at your own risk
\- runs on physical or virtual Linux desktop systems
\- cannot handle NOOBS images
\- do not shrink images to minimum, otherwise they won't start on your Raspberry, especially Raspbian Full *Desktop* images need some extra space, about >= 250 MB are advised, Raspbian *Lite* images might be more moderate
\- when starting from a shrinked SD card for the first time, expand the filesystem to fill its space
by raspi-config
`sudo raspi-config` -> *Expand Filesystem*
`sudo reboot`
**or** from command line
`sudo raspi-config --expand-rootfs`
`sudo reboot`
\- the script is 'half automatic', meaning at one point it will start GParted on desktop and guide you what to do
\- the script was developed and tested on a VirtualBox Windows host with Linux Mint guest
\- inspired by
[http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php](http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php)
Donations are welcome!
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=E7JNEDMHAJ3TJ)
- - -
#### history
V0.5
initial version, script keel fix by Barleyman
V0.6
mmcblk naming support
V0.7
simplifications
V0.71
adaption for parted 3.2, p -> print
- - -
#### copyright
shrink is published under the terms of ISC license
Copyright (c) 2018 [qrt@qland.de](mailto:qrt@qland.de)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================
FILE: deprecated/readme_081.md
================================================
# shrink
**Linux bash script to resize Raspberry SD card images**
consider further [remarks](#remarks)
### new version
\- automated size retrieving from GParted
\- progress bars with ETA for all time consuming actions
\- environment variable support
**not widely tested yet, be sure to have backups of your data**
or use [previous version](readme_071.md)
### download
download repository from GitHub,
unzip and copy for example to: ~/shrink
**or**
copy script to current directory
`wget https://raw.github.com/qrti/shrink/master/script/shrink.sh`
**or**
check if git is installed
`$ git --version`
if git is not installed
`$ sudo apt-get install git-all`
clone shrink repository to current directory
`$ git clone https://github.com/qrti/shrink.git`
- - -
### necessary installs
`$ sudo apt-get install gparted`
`$ sudo apt-get install pv`
- - -
### configure
before executing the script the first time, insert your SD card
enter the following at the command line and find the name of your SD device and partitions
`$ df -h`
edit the script and enter your data between the quotation marks
`$ nano shrink.sh`
example for /dev/sdb1 + 2 (omit digit)
```
DEVICE=${DEVICE:-/dev/sdb}
```
example for /dev/mmcblk0p1 + 2 (omit p and digit)
```
DEVICE=${DEVICE:-/dev/mmcblk0}
```
your username is filled in automatically, to override edit USER
```
USER=${USER:-`whoami`}
```
**using environment variables**
default values can be overridden by passing them as env vars
for example to set DEVICE and READ enter at the command line
`$ sudo DEVICE=/dev/sdb READ=false ./shrink.sh`
explore the top of the script to configure some more things
- - -
### execute
change directory
`$ cd ~/shrink`
make script executable once
`$ chmod 755 shrink.sh`
**or**
`$ chmod a+x shrink.sh`
execute script
`$ sudo ./shrink.sh`
- - -
### remarks
\- use this script completely at your own risk
\- runs on physical or virtual Linux desktop systems
\- cannot handle NOOBS images
\- do not shrink images to minimum, otherwise they won't start on your Raspberry, especially Raspbian Full *Desktop* images need some extra space, about >= 250 MB are advised, Raspbian *Lite* images might be more moderate
\- when starting from a shrinked SD card for the first time, expand the filesystem to fill its space
by raspi-config
`sudo raspi-config` -> *Expand Filesystem*
`sudo reboot`
**or**
from command line
`sudo raspi-config --expand-rootfs`
`sudo reboot`
\- the script is 'half automatic', meaning at one point it will start GParted on desktop and guide you what to do
\- progress display of 'fill empty space' may not end at 100 % exactly because of difficult file system overhead calculation, nevertheless space will be filled correctly
\- the script was developed and tested on a VirtualBox Windows host with Linux Mint guest
\- inspired by
[http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php](http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php)
Donations are welcome!
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=E7JNEDMHAJ3TJ)
- - -
### history
V0.5
initial version, script keel fix by Barleyman
V0.6
mmcblk naming support
V0.7
simplifications
V0.71
adaption for parted 3.2, p -> print
V0.8
automated size retrieving from GParted
progress bars with ETA for all time consuming actions
V0.81
default value override by environment variables
thanks to Leon Miller-Out
- - -
### copyright
shrink is published under the terms of ISC license
Copyright (c) 2018 [qrt@qland.de](mailto:qrt@qland.de)
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================
FILE: deprecated/shrink_071.sh
================================================
#!/bin/bash
# shrink V0.71 180527 qrt@qland.de
# linux bash script to resize Raspberry SD card images
#
# inspired by
# http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
#
# necessary installs
# sudo apt-get update && sudo apt-get install dcfldd
# sudo apt-get update && sudo apt-get install gparted
DEVICE="/dev/sdd" # source and target SD card device, examples: /dev/sdd, /dev/mmcblk0 ...
USER="your user name" # linux user name
IMAGE_NAME="image" # image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S")"
IMAGE="${IMAGE_NAME}.img" # image name with extension
LOOP=$(losetup -f)
READ=true # read image from SD card (false for an already existing image)
RESIZE=true # resize image with GParted
FILL=true # fill empty space of new image with zeroes, only possible if RESIZE=true
COMPRESS=false # compress new image (an extra file is generated)
WRITE=false # write new image to SD card
pause(){
printf "\n"
printf "$1\n"
read -p "press [Enter] to continue, CTRL-C to abort" key
printf "\n"
}
checkDevice(){
if [ "$1" == "" -o "$(df -h --output=source | grep "$DEVICE")" == "" ]; then
printf "device '$1' does not exist\n"
printf "> check SD card devices with 'df -h'\n"
printf "> re-insert SD card if necessary\n"
printf "> edit DEVICE= in script if necessary\n\n"
exit 1
fi
}
echo "shrink V0.71 180527 qrt@qland.de"
if [ $(id -u) -ne 0 ]; then
printf "\n"
printf "script must be run as root\n"
printf "> try 'sudo ./shrink'\n\n"
exit 1
fi
if [ "$USER" == "" ]; then
printf "\n"
printf "user not set\n"
printf "> edit USER= in script\n\n"
exit 1
fi
if [ $READ == true ]; then
if [ -f $IMAGE ]; then
pause "file '$IMAGE' already exists and will be overwritten"
echo -ne '\033[1A' # one line up
fi
pause "insert source SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
sudo umount $DEVICE?* && echo unmount ok || exit 1
sudo dcfldd if=$DEVICE of=$IMAGE && echo image read ok || exit 1
sudo sync
pause "remove SD card"
echo -ne '\033[1A' # one line up
fi
echo
sudo chown $USER.$USER $IMAGE && echo owner and group ok || exit 1
if [ $RESIZE == true ]; then
#sudo fdisk -l $IMAGE
#read -p "enter Start of part 2: " start
start="$(sudo parted $IMAGE -ms unit s print | grep "^2" | cut -f2 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP >/dev/null 2>&1 # remove possible open loop
sudo losetup $LOOP $IMAGE -o $((start*512)) && echo loop setup ok || exit 1
echo
echo "GParted desktop is started now"
echo "- go to GParted desktop window"
echo "- select '$LOOP'"
echo "- menu 'Partition / Resize/Move'"
echo "- change value of 'New Size' about >= 250 MB above 'Minimum Size'"
echo "- press button 'Resize/Move'"
echo "- menu 'Edit / Apply All Operations' and press Apply"
echo "- wait until GParted is ready - do not close dialog yet"
echo "- expand 'Details / Shrink.. / shrink.. / resize2fs -p $LOOP xxxxxxxK'"
echo "- note down size xxxxxxx"
echo "- close dialog and exit GParted"
sudo gparted $LOOP >/dev/null 2>&1 # supresses GLib messages
echo
read -p "enter noted size xxxxxxxx: " size
echo
sudo losetup -d $LOOP && echo loop remove ok || exit 1
sudo losetup $LOOP $IMAGE && echo loop setup ok || exit 1
newsize="+${size}K"
printf "d\n2\nn\np\n2\n$start\n$newsize\np\nw\n" | sudo fdisk $LOOP >/dev/null 2>&1
echo resize ok
#sudo fdisk -l $LOOP
#read -p "enter End of part 2: " end
end="$(sudo parted $LOOP -ms unit s print | grep "^2" | cut -f3 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP && echo loop remove ok || exit 1
truncate -s $(((end+1)*512)) $IMAGE && echo truncate ok || exit 1
if [ $FILL == true ]; then
echo
echo fill empty space
sudo losetup $LOOP $IMAGE -o $((start*512))
sudo mkdir -p /mnt/imageroot
sudo mount $LOOP /mnt/imageroot
sudo dcfldd if=/dev/zero of=/mnt/imageroot/zero.txt
sudo rm /mnt/imageroot/zero.txt
sudo umount /mnt/imageroot
sudo rmdir /mnt/imageroot
sudo losetup -d $LOOP
echo fill empty space ok
fi
fi
if [ $COMPRESS == true ]; then
echo
echo compress image
zip $IMAGE_NAME.zip $IMAGE && echo compress ok || echo compress failed
fi
if [ $WRITE == true ]; then
pause "insert target SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
sudo umount $DEVICE?* && echo unmount ok || exit 1
sudo dcfldd if=$IMAGE of=$DEVICE && echo image write ok || exit 1
sudo sync
echo
echo remove SD card
fi
echo
echo ready
echo
================================================
FILE: deprecated/shrink_081.sh
================================================
#!/bin/bash
# shrink V0.81 180707 qrt@qland.de
# linux bash script to resize Raspberry SD card images, progress version
#
# inspired by
# http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
# make script executable once
# chmod a+x shrink.sh
# necessary installs
# sudo apt-get install gparted
# sudo apt-get install pv
###
# configuration
# default values can be overridden by passing them as env vars
# e.g. sudo DEVICE=/dev/sda READ=false ./shrink.sh
###
USER=${USER:-`whoami`} # specify user who should own output files
DEVICE=${DEVICE:-/dev/sdb} # source and target SD card device, examples: /dev/sdd, /dev/mmcblk0 ...
IMAGE_NAME=${IMAGE_NAME:-image} # image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S")"
IMAGE=${IMAGE:-${IMAGE_NAME}.img} # image name with extension
DETAILS=${DETAILS:-~/gparted_details.htm} # gparted details file path and name
READ=${READ:-true} # read image from SD card (false for an already existing image)
RESIZE=${RESIZE:-true} # resize image with GParted
FILL=${FILL:-true} # fill empty space of new image with zeroes, only possible if RESIZE=true
COMPRESS=${COMPRESS:-false} # compress new image (an extra file is generated)
WRITE=${WRITE:-false} # write new image to SD card
LOOP=$(losetup -f)
pause(){
printf "\n"
printf "$1\n"
read -p "press [Enter] to continue, CTRL-C to abort" key
printf "\n"
}
checkDevice(){
if [ "$1" == "" -o "$(df -h --output=source | grep "$DEVICE")" == "" ]; then
printf "device '$1' does not exist\n"
printf "> check SD card devices with 'df -h'\n"
printf "> re-insert SD card if necessary\n"
printf "> edit DEVICE= in script if necessary\n\n"
exit 1
fi
}
echo "shrink V0.81 180707 qrt@qland.de"
if [ $(id -u) -ne 0 ]; then
printf "\n"
printf "script must be run as root\n"
printf "> try 'sudo ./shrink'\n\n"
exit 1
fi
if [ "$USER" == "" ]; then
printf "\n"
printf "user not set\n"
printf "> edit USER= in script\n\n"
exit 1
fi
if [ $READ == true ]; then
if [ -f $IMAGE ]; then
pause "file '$IMAGE' already exists and will be overwritten"
echo -ne '\033[1A' # one line up
fi
pause "insert source SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsize="$(($(blockdev --getsize64 $DEVICE)/1024))K"
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "generate image from SD card"
sudo dd if=$DEVICE status=none | pv -s $bsize | dd of=$IMAGE bs=4096 status=none \
&& echo image read ok || exit 1
sudo sync
pause "remove SD card"
echo -ne '\033[1A' # one line up
fi
echo
sudo chown $USER.$USER $IMAGE && echo owner and group ok || exit 1
if [ $RESIZE == true ]; then
#sudo fdisk -l $IMAGE
#read -p "enter Start of part 2: " start
start="$(sudo parted $IMAGE -ms unit s print | grep "^2" | cut -f2 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP >/dev/null 2>&1 # remove possible open loop
sudo losetup $LOOP $IMAGE -o $((start*512)) && echo loop setup ok || exit 1
echo
echo "GParted desktop is started now"
echo "- go to GParted desktop window"
echo "- select '$LOOP'"
echo "- menu 'Partition / Resize/Move'"
echo "- change value of 'New Size' about >= 250 MB above 'Minimum Size'"
echo "- press button 'Resize/Move'"
echo "- menu 'Edit / Apply All Operations' and press Apply"
echo "- wait until GParted is ready - do not close dialog yet"
echo "- press button 'Save Details' and 'Save' in file requester"
echo "- close dialog and exit GParted"
echo
rm -f ~/gparted_details.htm # remove old details
sudo gparted $LOOP >/dev/null 2>&1 # supresses GLib messages
if [ ! -f $DETAILS ]; then # check details exist
echo "gparted details file not found"
exit 1
fi
size=$(awk '/resize2fs -p / {print $4;}' $DETAILS | awk 'BEGIN { FS="K"; } { print $1; }')
rm -f ~/gparted_details.htm # remove details
if [ -z $size ]; then # check size
echo "size not found in details"
exit 1
elif [ $size -lt 512000 ]; then
echo "suspicious small filesize"
exit 1
fi
sudo losetup -d $LOOP && echo loop remove ok || exit 1
sudo losetup $LOOP $IMAGE && echo loop setup ok || exit 1
newsize="+${size}K"
printf "d\n2\nn\np\n2\n$start\n$newsize\np\nw\n" | sudo fdisk $LOOP >/dev/null 2>&1
echo resize ok
#sudo fdisk -l $LOOP
#read -p "enter End of part 2: " end
end="$(sudo parted $LOOP -ms unit s print | grep "^2" | cut -f3 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP && echo loop remove ok || exit 1
truncate -s $(((end+1)*512)) $IMAGE && echo truncate ok || exit 1
if [ $FILL == true ]; then
echo
echo fill empty space
sudo losetup $LOOP $IMAGE -o $((start*512))
sudo mkdir -p /mnt/imageroot
sudo mount $LOOP /mnt/imageroot
bsize="$(($(df -h -B1K | grep ^$LOOP | awk '{print $4}')*11/10))K" # +10% progress bar fs overhead correction
sudo dd if=/dev/zero | pv -s $bsize | dd of=/mnt/imageroot/zero.txt >/dev/null 2>&1
sudo rm /mnt/imageroot/zero.txt
sudo umount /mnt/imageroot
sudo rmdir /mnt/imageroot
sudo losetup -d $LOOP
echo fill empty space ok
fi
fi
if [ $COMPRESS == true ]; then
echo
echo compress image
tar pcf - $IMAGE | pv -s $(du -sb $IMAGE | awk '{print $1}') | gzip > $IMAGE_NAME.tar.gz \
&& echo compress ok || echo compress failed
fi
if [ $WRITE == true ]; then
pause "insert target SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsize="$(($(blockdev --getsize64 $DEVICE)/1024))K"
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "write image to SD card"
sudo dd if=$IMAGE status=none | pv -s $bsize | dd of=$DEVICE bs=4096 status=none \
&& echo image write ok || exit 1
sudo sync
echo
echo remove SD card
fi
echo
echo ready
echo
================================================
FILE: deprecated/shrink_092.sh
================================================
#!/bin/bash
# shrink V0.92 191008 qrt@qland.de
# linux bash script to resize Raspberry SD card images, progress version
#
# inspired by
# http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
# make script executable once
# chmod a+x shrink.sh
# necessary installs
# sudo apt-get install gparted
# sudo apt-get install pv
###
# configuration
# default values can be overridden by passing them as env vars
# e.g. sudo DEVICE=/dev/sda READ=false ./shrink.sh
###
SHRINK_VERSION="V0.92 191008"
trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR
USER=${USER:-`whoami`} # specify user who should own output files
DEVICE=${DEVICE:-/dev/sdb} # source and target SD card device, examples: /dev/sdd, /dev/mmcblk0 ...
IMAGE_NAME=${IMAGE_NAME:-image} # image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S")"
IMAGE=${IMAGE:-${IMAGE_NAME}.img} # image name with extension
DETAILS=${DETAILS:-~/gparted_details.htm} # gparted details file path and name
READ=${READ:-true} # read image from SD card (false for an already existing image)
RESIZE=${RESIZE:-true} # resize image with GParted
FILL=${FILL:-true} # fill empty space of new image with zeroes, only possible if RESIZE=true
COMPRESS=${COMPRESS:-false} # compress new image (an extra file is generated)
WRITE=${WRITE:-false} # write new image to SD card
LOOP=$(losetup -f)
_ME=$(basename "${0}")
_print_help() {
cat <<HEREDOC
Shrink ${SHRINK_VERSION} qrt@qland.de
Linux bash script to resize Raspberry SD card images, progress version.
Inspired by:
http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
Necessary steps:
make script executable once
chmod a+x shrink.sh
Necessary installs:
sudo apt-get install gparted
sudo apt-get install pv
Usage:
(sudo) ${_ME} [<arguments>]
(sudo) ${_ME} -h | --help
(sudo) ${_ME}
Options:
-h --help show this screen
--user specify user who should own output files (default: ${USER})
--device source and target SD card device (default: ${DEVICE})
--date_name image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S") (default: ${IMAGE_NAME})"
--image image name with extension (default: ${IMAGE})
--details gparted details file path and name (default: ${DETAILS})
--compress compress new image (an extra file is generated) (default: ${COMPRESS})
--write write new image to SD card (default: ${WRITE})
--skip-read read image from SD card (false for an already existing image) (default: ${READ})
--skip-resize resize image with GParted (default: ${RESIZE})
--skip-fill fill empty space of new image with zeroes, only possible if RESIZE=true (default: ${FILL})
HEREDOC
}
function _parse
{
# Gather commands
while (( "${#}" ))
do
case "${1}" in
--user)
USER="${2}"
shift
shift
;;
--device)
DEVICE="${2}"
shift
shift
;;
--date_name)
IMAGE_NAME="image_$(date +"%y%m%d%H%M%S")"
shift
;;
--image)
IMAGE="${2}"
shift
shift
;;
--details)
DETAILS="${2}"
shift
shift
;;
--skip-read)
READ=false
shift
;;
--skip-resize)
RESIZE=false
shift
;;
--skip-fill)
FILL=false
shift
;;
--compress)
COMPRESS=true
shift
;;
--write)
WRITE=true
shift
;;
*|-*|--*=) # unsupported flags
echo "Unknown ${1}"
exit 1
;;
esac
done
}
pause(){
printf "\n"
printf "$1\n"
read -p "press [Enter] to continue, CTRL-C to abort" key
printf "\n"
}
checkDevice(){
if [ "$1" == "" -o "$(df -h --output=source | grep "$DEVICE")" == "" ]; then
printf "device '$1' does not exist\n"
printf "> check SD card devices with 'df -h'\n"
printf "> re-insert SD card if necessary\n"
printf "> edit DEVICE= in script if necessary\n\n"
exit 1
fi
}
function _main
{
echo "shrink ${SHRINK_VERSION} qrt@qland.de"
if [ $(id -u) -ne 0 ]; then
printf "\n"
printf "script must be run as root\n"
printf "> try 'sudo ./shrink'\n\n"
exit 1
fi
if [ "$USER" == "" ]; then
printf "\n"
printf "user not set\n"
printf "> edit USER= in script\n\n"
exit 1
fi
if [ $READ == true ]; then
if [ -f $IMAGE ]; then
pause "file '$IMAGE' already exists and will be overwritten"
echo -ne '\033[1A' # one line up
fi
pause "insert source SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsizek=$(($(blockdev --getsize64 $DEVICE)/1024))
bsizem=$(($bsizek/1024))
freem=$((`df -k --output=avail "$PWD" | tail -n1`/1024))
if [ $freem -lt $(($bsizem*3)) ]; then
pause "warning: free memory "$freem"M is possibly too low for image (+ zip)"
echo -ne '\033[1A' # one line up
fi
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "generate image from SD card"
bsize=$bsizek"K"
sudo dd if=$DEVICE status=none | pv -s $bsize | dd of=$IMAGE bs=4096 status=none \
&& echo image read ok || exit 1
sudo sync
pause "remove SD card"
echo -ne '\033[1A' # one line up
fi
echo
sudo chown $USER.$USER $IMAGE && echo owner and group ok || exit 1
if [ $RESIZE == true ]; then
#sudo fdisk -l $IMAGE
#read -p "enter Start of part 2: " start
start="$(sudo parted $IMAGE -ms unit s print | grep "^2" | cut -f2 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d ${LOOP} >/dev/null 2>&1 # remove possible open loop
sudo losetup ${LOOP} ${IMAGE} -o $((start*512)) && echo loop setup ok || exit 1
echo
echo "GParted desktop is started now"
echo "- go to GParted desktop window"
echo "- select '$LOOP'"
echo "- menu 'Partition / Resize/Move'"
echo "- change value of 'New Size' about >= 250 MB above 'Minimum Size'"
echo "- press button 'Resize/Move'"
echo "- menu 'Edit / Apply All Operations' and press Apply"
echo "- wait until GParted is ready - do not close dialog yet"
echo "- press button 'Save Details' and 'Save' in file requester"
echo " details are saved to $DETAILS"
echo "- close dialog and exit GParted"
echo
rm -f ~/gparted_details.htm # remove old details
sudo gparted $LOOP >/dev/null 2>&1 # supresses GLib messages
if [ ! -f $DETAILS ]; then # check details exist
echo "gparted details file not found"
exit 1
fi
size=$(awk '/resize2fs -p / {print $4;}' $DETAILS | awk 'BEGIN { FS="K"; } { print $1; }')
rm -f ~/gparted_details.htm # remove details
if [ -z $size ]; then # check size
echo "size not found in details"
exit 1
elif [ $size -lt 512000 ]; then
echo "suspicious small filesize"
exit 1
fi
sudo losetup -d $LOOP && echo loop remove ok || exit 1
sudo losetup $LOOP $IMAGE && echo loop setup ok || exit 1
newsize="+${size}K"
printf "d\n2\nn\np\n2\n$start\n$newsize\np\nw\n" | sudo fdisk $LOOP >/dev/null 2>&1
echo resize ok
#sudo fdisk -l $LOOP
#read -p "enter End of part 2: " end
end="$(sudo parted $LOOP -ms unit s print | grep "^2" | cut -f3 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP && echo loop remove ok || exit 1
truncate -s $(((end+1)*512)) $IMAGE && echo truncate ok || exit 1
if [ $FILL == true ]; then
echo
echo fill empty space
sudo losetup $LOOP $IMAGE -o $((start*512))
sudo mkdir -p /mnt/imageroot
sudo mount $LOOP /mnt/imageroot
bsize="$(($(df -h -B1K | grep ^$LOOP | awk '{print $4}')*11/10))K" # +10% progress bar fs overhead correction
sudo dd if=/dev/zero | pv -s $bsize | dd of=/mnt/imageroot/zero.txt >/dev/null 2>&1
sudo rm /mnt/imageroot/zero.txt
sudo umount /mnt/imageroot
sudo rmdir /mnt/imageroot
sudo losetup -d $LOOP
echo fill empty space ok
fi
fi
if [ $COMPRESS == true ]; then
echo
echo compress image
tar pcf - $IMAGE | pv -s $(du -sb $IMAGE | awk '{print $1}') | gzip > $IMAGE_NAME.tar.gz \
&& echo compress ok || echo compress failed
fi
if [ $WRITE == true ]; then
pause "insert target SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsize="$(($(blockdev --getsize64 $DEVICE)/1024))K"
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "write image to SD card"
sudo dd if=$IMAGE status=none | pv -s $bsize | dd of=$DEVICE bs=4096 status=none \
&& echo image write ok || exit 1
sudo sync
echo
echo remove SD card
fi
echo
echo ready
echo
}
if [ "${1:-}" == -h ] || [ "${1:-}" == --help ]; then
_print_help
else
# check script dependencies
command -v gparted >/dev/null 2>&1 || { echo >&2 "Cannot locate gparted. Is it installed? Aborting."; exit 1; }
command -v pv >/dev/null 2>&1 || { echo >&2 "Cannot locate pv. Is it installed? Aborting."; exit 1; }
echo "calling parser"
_parse "$@"
_main "$@"
fi
================================================
FILE: script/shrink.sh
================================================
#!/bin/bash
# shrink V0.93 241231 qrt@qland.de
# linux bash script to resize Raspberry SD card images, progress version
#
# inspired by
# http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
# make script executable once
# chmod a+x shrink.sh
# necessary installs
# sudo apt-get install gparted
# sudo apt-get install pv
###
# configuration
# default values can be overridden by passing them as env vars
# e.g. sudo DEVICE=/dev/sda READ=false ./shrink.sh
###
SHRINK_VERSION="V0.93 241231"
trap 'echo "Aborting due to errexit on line $LINENO. Exit code: $?" >&2' ERR
USER=${USER:-`whoami`} # specify user who should own output files
DEVICE=${DEVICE:-/dev/sdb} # source and target SD card device, examples: /dev/sdd, /dev/mmcblk0 ...
IMAGE_NAME=${IMAGE_NAME:-image} # image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S")"
IMAGE=${IMAGE:-${IMAGE_NAME}.img} # image name with extension
DETAILS=${DETAILS:-~/gparted_details.htm} # gparted details file path and name
READ=${READ:-true} # read image from SD card (false for an already existing image)
RESIZE=${RESIZE:-true} # resize image with GParted
FILL=${FILL:-true} # fill empty space of new image with zeroes, only possible if RESIZE=true
COMPRESS=${COMPRESS:-false} # compress new image (an extra file is generated)
WRITE=${WRITE:-false} # write new image to SD card
LOOP=$(losetup -f)
_ME=$(basename "${0}")
_print_help() {
cat <<HEREDOC
Shrink ${SHRINK_VERSION} qrt@qland.de
Linux bash script to resize Raspberry SD card images, progress version.
Inspired by:
http://www.aoakley.com/articles/2015-10-09-resizing-sd-images.php
Necessary steps:
make script executable once
chmod a+x shrink.sh
Necessary installs:
sudo apt-get install gparted
sudo apt-get install pv
Usage:
(sudo) ${_ME} [<arguments>]
(sudo) ${_ME} -h | --help
(sudo) ${_ME}
Options:
-h --help show this screen
--user specify user who should own output files (default: ${USER})
--device source and target SD card device (default: ${DEVICE})
--date_name image name, alternative with date and time: "image_$(date +"%y%m%d%H%M%S") (default: ${IMAGE_NAME})"
--image image name with extension (default: ${IMAGE})
--details gparted details file path and name (default: ${DETAILS})
--compress compress new image (an extra file is generated) (default: ${COMPRESS})
--write write new image to SD card (default: ${WRITE})
--skip-read read image from SD card (false for an already existing image) (default: ${READ})
--skip-resize resize image with GParted (default: ${RESIZE})
--skip-fill fill empty space of new image with zeroes, only possible if RESIZE=true (default: ${FILL})
HEREDOC
}
function _parse
{
# Gather commands
while (( "${#}" ))
do
case "${1}" in
--user)
USER="${2}"
shift
shift
;;
--device)
DEVICE="${2}"
shift
shift
;;
--date_name)
IMAGE_NAME="image_$(date +"%y%m%d%H%M%S")"
shift
;;
--image)
IMAGE="${2}"
shift
shift
;;
--details)
DETAILS="${2}"
shift
shift
;;
--skip-read)
READ=false
shift
;;
--skip-resize)
RESIZE=false
shift
;;
--skip-fill)
FILL=false
shift
;;
--compress)
COMPRESS=true
shift
;;
--write)
WRITE=true
shift
;;
*|-*|--*=) # unsupported flags
echo "Unknown ${1}"
exit 1
;;
esac
done
}
pause(){
printf "\n"
printf "$1\n"
read -p "press [Enter] to continue, CTRL-C to abort" key
printf "\n"
}
checkDevice(){
if [ "$1" == "" -o "$(df -h --output=source | grep "$DEVICE")" == "" ]; then
printf "device '$1' does not exist\n"
printf "> check SD card devices with 'df -h'\n"
printf "> re-insert SD card if necessary\n"
printf "> edit DEVICE= in script if necessary\n\n"
exit 1
fi
}
function _main
{
echo "shrink ${SHRINK_VERSION} qrt@qland.de"
if [ $(id -u) -ne 0 ]; then
printf "\n"
printf "script must be run as root\n"
printf "> try 'sudo ./shrink'\n\n"
exit 1
fi
if [ "$USER" == "" ]; then
printf "\n"
printf "user not set\n"
printf "> edit USER= in script\n\n"
exit 1
fi
if [ $READ == true ]; then
if [ -f $IMAGE ]; then
pause "file '$IMAGE' already exists and will be overwritten"
echo -ne '\033[1A' # one line up
fi
pause "insert source SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsizek=$(($(blockdev --getsize64 $DEVICE)/1024))
bsizem=$(($bsizek/1024))
freem=$((`df -k --output=avail "$PWD" | tail -n1`/1024))
if [ $freem -lt $(($bsizem*3)) ]; then
pause "warning: free memory "$freem"M is possibly too low for image (+ zip)"
echo -ne '\033[1A' # one line up
fi
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "generate image from SD card"
bsize=$bsizek"K"
sudo dd if=$DEVICE status=none | pv -s $bsize | dd of=$IMAGE bs=4096 status=none \
&& echo image read ok || exit 1
sudo sync
pause "remove SD card"
echo -ne '\033[1A' # one line up
fi
echo
sudo chown $USER:$USER $IMAGE && echo owner and group ok || exit 1
if [ $RESIZE == true ]; then
#sudo fdisk -l $IMAGE
#read -p "enter Start of part 2: " start
start="$(sudo parted $IMAGE -ms unit s print | grep "^2" | cut -f2 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d ${LOOP} >/dev/null 2>&1 # remove possible open loop
sudo losetup ${LOOP} ${IMAGE} -o $((start*512)) && echo loop setup ok || exit 1
echo
echo "GParted desktop is started now"
echo "- go to GParted desktop window"
echo "- select '$LOOP'"
echo "- menu 'Partition / Resize/Move'"
echo "- change value of 'New Size' about >= 250 MB above 'Minimum Size'"
echo "- press button 'Resize/Move'"
echo "- menu 'Edit / Apply All Operations' and press Apply"
echo "- wait until GParted is ready - do not close dialog yet"
echo "- press button 'Save Details' and 'Save' in file requester"
echo " details are saved to $DETAILS"
echo "- close dialog and exit GParted"
echo
rm -f ~/gparted_details.htm # remove old details
sudo gparted $LOOP >/dev/null 2>&1 # supresses GLib messages
if [ ! -f $DETAILS ]; then # check details exist
echo "gparted details file not found"
exit 1
fi
size=$(awk '/resize2fs -p / {print $4;}' $DETAILS | awk 'BEGIN { FS="K"; } { print $1; }')
rm -f ~/gparted_details.htm # remove details
if [ -z $size ]; then # check size
echo "size not found in details"
exit 1
elif [ $size -lt 512000 ]; then
echo "suspicious small filesize"
exit 1
fi
sudo losetup -d $LOOP && echo loop remove ok || exit 1
sudo losetup $LOOP $IMAGE && echo loop setup ok || exit 1
newsize="+${size}K"
printf "d\n2\nn\np\n2\n$start\n$newsize\np\nw\n" | sudo fdisk $LOOP >/dev/null 2>&1
echo resize ok
#sudo fdisk -l $LOOP
#read -p "enter End of part 2: " end
end="$(sudo parted $LOOP -ms unit s print | grep "^2" | cut -f3 -d: | sed 's/[^0-9]*//g')"
sudo losetup -d $LOOP && echo loop remove ok || exit 1
truncate -s $(((end+1)*512)) $IMAGE && echo truncate ok || exit 1
if [ $FILL == true ]; then
echo
echo fill empty space
sudo losetup $LOOP $IMAGE -o $((start*512))
sudo mkdir -p /mnt/imageroot
sudo mount $LOOP /mnt/imageroot
bsize="$(($(df -h -B1K | grep ^$LOOP | awk '{print $4}')*11/10))K" # +10% progress bar fs overhead correction
sudo dd if=/dev/zero | pv -s $bsize | dd of=/mnt/imageroot/zero.txt >/dev/null 2>&1
sudo rm /mnt/imageroot/zero.txt
sudo umount /mnt/imageroot
sudo rmdir /mnt/imageroot
sudo losetup -d $LOOP
echo fill empty space ok
fi
fi
if [ $COMPRESS == true ]; then
echo
echo compress image
tar pcf - $IMAGE | pv -s $(du -sb $IMAGE | awk '{print $1}') | gzip > $IMAGE_NAME.tar.gz \
&& echo compress ok || echo compress failed
fi
if [ $WRITE == true ]; then
pause "insert target SD card and >>> close all popup file manager windows <<<"
checkDevice $DEVICE
bsize="$(($(blockdev --getsize64 $DEVICE)/1024))K"
sudo umount $DEVICE?* && echo unmount ok || exit 1
echo
echo "write image to SD card"
sudo dd if=$IMAGE status=none | pv -s $bsize | dd of=$DEVICE bs=4096 status=none \
&& echo image write ok || exit 1
sudo sync
echo
echo remove SD card
fi
echo
echo ready
echo
}
if [ "${1:-}" == -h ] || [ "${1:-}" == --help ]; then
_print_help
else
# check script dependencies
command -v gparted >/dev/null 2>&1 || { echo >&2 "Cannot locate gparted. Is it installed? Aborting."; exit 1; }
command -v pv >/dev/null 2>&1 || { echo >&2 "Cannot locate pv. Is it installed? Aborting."; exit 1; }
echo "calling parser"
_parse "$@"
_main "$@"
fi
gitextract_ilp038ff/
├── .gitattributes
├── README.md
├── deprecated/
│ ├── readme_071.md
│ ├── readme_081.md
│ ├── shrink_071.sh
│ ├── shrink_081.sh
│ └── shrink_092.sh
└── script/
└── shrink.sh
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
{
"path": ".gitattributes",
"chars": 378,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs diff=csharp\n\n# St"
},
{
"path": "README.md",
"chars": 6466,
"preview": "# **shrink**\n\n**Linux bash script to resize Raspberry SD card images** \nconsider further [remarks](#remarks)\n\n### **new"
},
{
"path": "deprecated/readme_071.md",
"chars": 3660,
"preview": "# shrink V0.71\nthere is also a [newer version](README.md)\n\n#### Linux bash script to resize Raspberry SD card images \nc"
},
{
"path": "deprecated/readme_081.md",
"chars": 4448,
"preview": "# shrink\n\n**Linux bash script to resize Raspberry SD card images** \nconsider further [remarks](#remarks)\n\n### new versi"
},
{
"path": "deprecated/shrink_071.sh",
"chars": 5012,
"preview": "#!/bin/bash\n\n# shrink V0.71 180527 qrt@qland.de\n# linux bash script to resize Raspberry SD card images \n#\n# inspired by\n"
},
{
"path": "deprecated/shrink_081.sh",
"chars": 6437,
"preview": "#!/bin/bash\n\n# shrink V0.81 180707 qrt@qland.de\n# linux bash script to resize Raspberry SD card images, progress version"
},
{
"path": "deprecated/shrink_092.sh",
"chars": 10391,
"preview": "#!/bin/bash\n\n# shrink V0.92 191008 qrt@qland.de\n# linux bash script to resize Raspberry SD card images, progress version"
},
{
"path": "script/shrink.sh",
"chars": 10391,
"preview": "#!/bin/bash\n\n# shrink V0.93 241231 qrt@qland.de\n# linux bash script to resize Raspberry SD card images, progress version"
}
]
About this extraction
This page contains the full source code of the qrti/shrink GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (46.1 KB), approximately 12.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.