Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
(Brought over from SE.) This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs ...
#3: Post edited
- _(Brought over from [SE](https://codereview.stackexchange.com/q/209507/98306).)_
- <hr />
- This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs it requires and the test I used so that you can test it too.
- Any comments regarding programming style and improvements are welcome.
- <hr />
- ## Overview
- The following is a Bash shell script that copies files stored inside disk images into a directory in the filesystem.
- The script takes two parameters:
- * The first one is optional and defines a root directory (existing or not) that will contain the files being copied.
- * The second one, optional when the first one is given, is a path to a valid JSON-formatted file that describes:
- 1. which disk images will be opened,
- 2. which files inside each disk image will be copied, and
- 3. which path inside the directory root will be used as the destination for the files being copied.
- The first parameter defaults to the current directory when not given. The second one defaults to a file named `steps.json` located in the current directory. If the first parameter is not given, the second one can't be either.
- ## Prerequisites
- This script requires the following external programs to work correctly:
- * The JSON parsing program `jq`.
- * The disk image manipulation utility `udisksctl`.
- To install these dependencies, use one of the following commands:
- * Ubuntu
- $ sudo apt install jq udisks2
- * Fedora
- $ sudo dnf install jq udisks2
- ## Script
- The complete script is below. It can be marked as executable to avoid having to prepend `bash` to its execution command. There is no restrictions on directories this script may reside into. For the purpose of the test below, the directory where it resides has read/write permissions.
- ### `imgdisk-copy.sh`
- #!/bin/bash
- # Copying files contained inside disk images via JSON recipe.
# logo_writer- # December 12th, 2018
- # Is a string contained in another? Return 0 if so; 1 if not.
- # By fjarlq, from https://stackoverflow.com/a/8811800/5397930
- contains() {
- string="$1"
- substring="$2"
- if test "${string#*$substring}" != "$string"; then
- return 0
- else
- return 1
- fi
- }
- # Obtain the absolute path of a given directory.
- # By dogbane, from https://stackoverflow.com/a/3915420
- abspath() {
- dir="$1"
- echo "$(cd "$(dirname "$dir")"; pwd -P)/$(basename "$dir")"
- }
- # The main script starts here.
- # If no first parameter is given, assume current directory.
- if [ -z "$1" ]; then
- DESTROOT="."
- else
- # Omit any trailing slash
- DESTROOT=$(abspath "${1%/}")
- fi
- # If no second parameter is given, assume file "steps.json".
- # If no first parameter is given, this can't be either.
- if [ -z "$2" ]; then
- CONF="./steps.json"
- else
- CONF="$2"
- fi
- # Create the root directory where the files will the put.
- mkdir -p "$DESTROOT"
- # How many disks will be processed?
- LIMIT=$(cat "$CONF" | jq -r length)
- i=0
- while [ "$i" -lt "$LIMIT" ]; do
- # For each disk, get its file name.
- DISK=$(cat "$CONF" | jq -r .["$i"].disk)
- echo "$DISK"
- # Setup a loop device for the disk and get its name.
- RES=$(udisksctl loop-setup -f "$DISK")
- LOOP=$(echo "$RES" | cut -f5 -d' ' | head -c -2)
- # Using the loop device obtained, mount the disk.
- # Obtain the mount root directory afterwards.
- RES=$(udisksctl mount -b "$LOOP")
- SRCDIR=$(echo "$RES" | sed -nE 's|.*at (.*)\.|\1|p')
- # How many file sets will be copied?
- NOITEMS=$(cat "$CONF" | jq -r ".["$i"].files | length")
- j=0
- while [ "$j" -lt "$NOITEMS" ]; do
- # For each file set, obtain which files will be copied and where.
- FSRC=$(cat "$CONF" | jq -r .["$i"].files["$j"].src)
- FDEST=$(cat "$CONF" | jq -r .["$i"].files["$j"].dest)
- # Make the destination directory.
- mkdir -p "$DESTROOT"/"$FDEST"
- echo " ""$FSRC"
- if contains "$FSRC" "\*"; then
- # If a wildcard is used in the file set, copy by file expansion (option -t).
- pushd "$SRCDIR" > /dev/null
- cp -t "$DESTROOT"/"$FDEST" $FSRC
- popd > /dev/null
- else
- # Else, copy normally.
- cp "$SRCDIR"/"$FSRC" "$DESTROOT"/"$FDEST"
- fi
- j=$(($j + 1))
- done
- # Once all the file sets are copied, unmount the disk
- # and delete its associated loop device.
- udisksctl unmount -b "$LOOP" > /dev/null
- udisksctl loop-delete -b "$LOOP"
- i=$(($i + 1))
- done
- ## Test set
- This script was tested with the following disk set: [Microsoft C Compiler 4.0](https://winworldpc.com/download/1ce2809c-2b4c-e280-9804-11c3a6e28094). The first 3 `.img` disks inside the ZIP (`disk01.img`, `disk02.img`, and `disk03.img`) should be placed in the same directory the script is.
- The corresponding JSON recipe used for the test is below. It is also placed in the same directory the script is for convenience.
- ### `steps.json`
- [
- {
- "disk": "disk01.img",
- "files": [
- { "src": "*", "dest": "bin" }
- ]
- },
- {
- "disk": "disk02.img",
- "files": [
- { "src": "*.EXE", "dest": "bin" }
- ]
- },
- {
- "disk": "disk03.img",
- "files": [
- { "src": "LINK.EXE", "dest": "bin" },
- { "src": "*.H", "dest": "include" },
- { "src": "SYS/*.H", "dest": "include/sys" },
- { "src": "SLIBC.LIB", "dest": "lib" },
- { "src": "SLIBFP.LIB", "dest": "lib" },
- { "src": "EM.LIB", "dest": "lib" },
- { "src": "LIBH.LIB", "dest": "lib" }
- ]
- }
- ]
- The test is performed by opening a terminal and executing the following command:
- $ ./imgdisk-copy.sh testing/
- The command will output each disk image name as it is mounted, and under it the names of the files being copied (unexpanded), as follows:
- disk01.img
- *
- disk02.img
- *.EXE
- disk03.img
- LINK.EXE
- *.H
- SYS/*.H
- SLIBC.LIB
- SLIBFP.LIB
- EM.LIB
- LIBH.LIB
- The result will be a directory `testing` under where the script is with the following structure:
- testing/
- ├── bin
- │ ├── C1.EXE
- │ ├── C2.EXE
- │ ├── C3.EXE
- │ ├── CL.EXE
- │ ├── CV.EXE
- │ ├── EXEMOD.EXE
- │ ├── EXEPACK.EXE
- │ ├── LIB.EXE
- │ ├── LINK.EXE
- │ ├── MAKE.EXE
- │ ├── MSC.EXE
- │ └── SETENV.EXE
- ├── include
- │ ├── sys
- │ │ ├── LOCKING.H
- │ │ ├── STAT.H
- │ │ ├── TIMEB.H
- │ │ ├── TYPES.H
- │ │ └── UTIME.H
- │ ├── ASSERT.H
- │ ├── CONIO.H
- │ ├── CTYPE.H
- │ ├── DIRECT.H
- │ ├── DOS.H
- │ ├── ERRNO.H
- │ ├── FCNTL.H
- │ ├── FLOAT.H
- │ ├── IO.H
- │ ├── LIMITS.H
- │ ├── MALLOC.H
- │ ├── MATH.H
- │ ├── MEMORY.H
- │ ├── PROCESS.H
- │ ├── SEARCH.H
- │ ├── SETJMP.H
- │ ├── SHARE.H
- │ ├── SIGNAL.H
- │ ├── STDARG.H
- │ ├── STDDEF.H
- │ ├── STDIO.H
- │ ├── STDLIB.H
- │ ├── STRING.H
- │ ├── TIME.H
- │ ├── V2TOV3.H
- │ └── VARARGS.H
- └── lib
- ├── EM.LIB
- ├── LIBH.LIB
- ├── SLIBC.LIB
- └── SLIBFP.LIB
- _(Brought over from [SE](https://codereview.stackexchange.com/q/209507/98306).)_
- <hr />
- This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs it requires and the test I used so that you can test it too.
- Any comments regarding programming style and improvements are welcome.
- <hr />
- ## Overview
- The following is a Bash shell script that copies files stored inside disk images into a directory in the filesystem.
- The script takes two parameters:
- * The first one is optional and defines a root directory (existing or not) that will contain the files being copied.
- * The second one, optional when the first one is given, is a path to a valid JSON-formatted file that describes:
- 1. which disk images will be opened,
- 2. which files inside each disk image will be copied, and
- 3. which path inside the directory root will be used as the destination for the files being copied.
- The first parameter defaults to the current directory when not given. The second one defaults to a file named `steps.json` located in the current directory. If the first parameter is not given, the second one can't be either.
- ## Prerequisites
- This script requires the following external programs to work correctly:
- * The JSON parsing program `jq`.
- * The disk image manipulation utility `udisksctl`.
- To install these dependencies, use one of the following commands:
- * Ubuntu
- $ sudo apt install jq udisks2
- * Fedora
- $ sudo dnf install jq udisks2
- ## Script
- The complete script is below. It can be marked as executable to avoid having to prepend `bash` to its execution command. There is no restrictions on directories this script may reside into. For the purpose of the test below, the directory where it resides has read/write permissions.
- ### `imgdisk-copy.sh`
- #!/bin/bash
- # Copying files contained inside disk images via JSON recipe.
- # Aura Lesse Programmer
- # December 12th, 2018
- # Is a string contained in another? Return 0 if so; 1 if not.
- # By fjarlq, from https://stackoverflow.com/a/8811800/5397930
- contains() {
- string="$1"
- substring="$2"
- if test "${string#*$substring}" != "$string"; then
- return 0
- else
- return 1
- fi
- }
- # Obtain the absolute path of a given directory.
- # By dogbane, from https://stackoverflow.com/a/3915420
- abspath() {
- dir="$1"
- echo "$(cd "$(dirname "$dir")"; pwd -P)/$(basename "$dir")"
- }
- # The main script starts here.
- # If no first parameter is given, assume current directory.
- if [ -z "$1" ]; then
- DESTROOT="."
- else
- # Omit any trailing slash
- DESTROOT=$(abspath "${1%/}")
- fi
- # If no second parameter is given, assume file "steps.json".
- # If no first parameter is given, this can't be either.
- if [ -z "$2" ]; then
- CONF="./steps.json"
- else
- CONF="$2"
- fi
- # Create the root directory where the files will the put.
- mkdir -p "$DESTROOT"
- # How many disks will be processed?
- LIMIT=$(cat "$CONF" | jq -r length)
- i=0
- while [ "$i" -lt "$LIMIT" ]; do
- # For each disk, get its file name.
- DISK=$(cat "$CONF" | jq -r .["$i"].disk)
- echo "$DISK"
- # Setup a loop device for the disk and get its name.
- RES=$(udisksctl loop-setup -f "$DISK")
- LOOP=$(echo "$RES" | cut -f5 -d' ' | head -c -2)
- # Using the loop device obtained, mount the disk.
- # Obtain the mount root directory afterwards.
- RES=$(udisksctl mount -b "$LOOP")
- SRCDIR=$(echo "$RES" | sed -nE 's|.*at (.*)\.|\1|p')
- # How many file sets will be copied?
- NOITEMS=$(cat "$CONF" | jq -r ".["$i"].files | length")
- j=0
- while [ "$j" -lt "$NOITEMS" ]; do
- # For each file set, obtain which files will be copied and where.
- FSRC=$(cat "$CONF" | jq -r .["$i"].files["$j"].src)
- FDEST=$(cat "$CONF" | jq -r .["$i"].files["$j"].dest)
- # Make the destination directory.
- mkdir -p "$DESTROOT"/"$FDEST"
- echo " ""$FSRC"
- if contains "$FSRC" "\*"; then
- # If a wildcard is used in the file set, copy by file expansion (option -t).
- pushd "$SRCDIR" > /dev/null
- cp -t "$DESTROOT"/"$FDEST" $FSRC
- popd > /dev/null
- else
- # Else, copy normally.
- cp "$SRCDIR"/"$FSRC" "$DESTROOT"/"$FDEST"
- fi
- j=$(($j + 1))
- done
- # Once all the file sets are copied, unmount the disk
- # and delete its associated loop device.
- udisksctl unmount -b "$LOOP" > /dev/null
- udisksctl loop-delete -b "$LOOP"
- i=$(($i + 1))
- done
- ## Test set
- This script was tested with the following disk set: [Microsoft C Compiler 4.0](https://winworldpc.com/download/1ce2809c-2b4c-e280-9804-11c3a6e28094). The first 3 `.img` disks inside the ZIP (`disk01.img`, `disk02.img`, and `disk03.img`) should be placed in the same directory the script is.
- The corresponding JSON recipe used for the test is below. It is also placed in the same directory the script is for convenience.
- ### `steps.json`
- [
- {
- "disk": "disk01.img",
- "files": [
- { "src": "*", "dest": "bin" }
- ]
- },
- {
- "disk": "disk02.img",
- "files": [
- { "src": "*.EXE", "dest": "bin" }
- ]
- },
- {
- "disk": "disk03.img",
- "files": [
- { "src": "LINK.EXE", "dest": "bin" },
- { "src": "*.H", "dest": "include" },
- { "src": "SYS/*.H", "dest": "include/sys" },
- { "src": "SLIBC.LIB", "dest": "lib" },
- { "src": "SLIBFP.LIB", "dest": "lib" },
- { "src": "EM.LIB", "dest": "lib" },
- { "src": "LIBH.LIB", "dest": "lib" }
- ]
- }
- ]
- The test is performed by opening a terminal and executing the following command:
- $ ./imgdisk-copy.sh testing/
- The command will output each disk image name as it is mounted, and under it the names of the files being copied (unexpanded), as follows:
- disk01.img
- *
- disk02.img
- *.EXE
- disk03.img
- LINK.EXE
- *.H
- SYS/*.H
- SLIBC.LIB
- SLIBFP.LIB
- EM.LIB
- LIBH.LIB
- The result will be a directory `testing` under where the script is with the following structure:
- testing/
- ├── bin
- │ ├── C1.EXE
- │ ├── C2.EXE
- │ ├── C3.EXE
- │ ├── CL.EXE
- │ ├── CV.EXE
- │ ├── EXEMOD.EXE
- │ ├── EXEPACK.EXE
- │ ├── LIB.EXE
- │ ├── LINK.EXE
- │ ├── MAKE.EXE
- │ ├── MSC.EXE
- │ └── SETENV.EXE
- ├── include
- │ ├── sys
- │ │ ├── LOCKING.H
- │ │ ├── STAT.H
- │ │ ├── TIMEB.H
- │ │ ├── TYPES.H
- │ │ └── UTIME.H
- │ ├── ASSERT.H
- │ ├── CONIO.H
- │ ├── CTYPE.H
- │ ├── DIRECT.H
- │ ├── DOS.H
- │ ├── ERRNO.H
- │ ├── FCNTL.H
- │ ├── FLOAT.H
- │ ├── IO.H
- │ ├── LIMITS.H
- │ ├── MALLOC.H
- │ ├── MATH.H
- │ ├── MEMORY.H
- │ ├── PROCESS.H
- │ ├── SEARCH.H
- │ ├── SETJMP.H
- │ ├── SHARE.H
- │ ├── SIGNAL.H
- │ ├── STDARG.H
- │ ├── STDDEF.H
- │ ├── STDIO.H
- │ ├── STDLIB.H
- │ ├── STRING.H
- │ ├── TIME.H
- │ ├── V2TOV3.H
- │ └── VARARGS.H
- └── lib
- ├── EM.LIB
- ├── LIBH.LIB
- ├── SLIBC.LIB
- └── SLIBFP.LIB
#2: Post edited
- _(Brought over from [SE](https://codereview.stackexchange.com/q/209507/98306).)_
- <hr />
- This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs it requires and the test I used so that you can test it too.
- Any comments regarding programming style and improvements are welcome.
- <hr />
- ## Overview
- The following is a Bash shell script that copies files stored inside disk images into a directory in the filesystem.
- The script takes two parameters:
- * The first one is optional and defines a root directory (existing or not) that will contain the files being copied.
- * The second one, optional when the first one is given, is a path to a valid JSON-formatted file that describes:
- 1. which disk images will be opened,
- 2. which files inside each disk image will be copied, and
- 3. which path inside the directory root will be used as the destination for the files being copied.
- The first parameter defaults to the current directory when not given. The second one defaults to a file named `steps.json` located in the current directory. If the first parameter is not given, the second one can't be either.
- ## Prerequisites
- This script requires the following external programs to work correctly:
- * The JSON parsing program `jq`.
- * The disk image manipulation utility `udisksctl`.
In Ubuntu, these programs can be installed with the following command:$ sudo apt install jq udisks2- ## Script
- The complete script is below. It can be marked as executable to avoid having to prepend `bash` to its execution command. There is no restrictions on directories this script may reside into. For the purpose of the test below, the directory where it resides has read/write permissions.
- ### `imgdisk-copy.sh`
- #!/bin/bash
- # Copying files contained inside disk images via JSON recipe.
- # logo_writer
- # December 12th, 2018
- # Is a string contained in another? Return 0 if so; 1 if not.
- # By fjarlq, from https://stackoverflow.com/a/8811800/5397930
- contains() {
- string="$1"
- substring="$2"
- if test "${string#*$substring}" != "$string"; then
- return 0
- else
- return 1
- fi
- }
- # Obtain the absolute path of a given directory.
- # By dogbane, from https://stackoverflow.com/a/3915420
- abspath() {
- dir="$1"
- echo "$(cd "$(dirname "$dir")"; pwd -P)/$(basename "$dir")"
- }
- # The main script starts here.
- # If no first parameter is given, assume current directory.
- if [ -z "$1" ]; then
- DESTROOT="."
- else
- # Omit any trailing slash
- DESTROOT=$(abspath "${1%/}")
- fi
- # If no second parameter is given, assume file "steps.json".
- # If no first parameter is given, this can't be either.
- if [ -z "$2" ]; then
- CONF="./steps.json"
- else
- CONF="$2"
- fi
- # Create the root directory where the files will the put.
- mkdir -p "$DESTROOT"
- # How many disks will be processed?
- LIMIT=$(cat "$CONF" | jq -r length)
- i=0
- while [ "$i" -lt "$LIMIT" ]; do
- # For each disk, get its file name.
- DISK=$(cat "$CONF" | jq -r .["$i"].disk)
- echo "$DISK"
- # Setup a loop device for the disk and get its name.
- RES=$(udisksctl loop-setup -f "$DISK")
- LOOP=$(echo "$RES" | cut -f5 -d' ' | head -c -2)
- # Using the loop device obtained, mount the disk.
- # Obtain the mount root directory afterwards.
- RES=$(udisksctl mount -b "$LOOP")
- SRCDIR=$(echo "$RES" | sed -nE 's|.*at (.*)\.|\1|p')
- # How many file sets will be copied?
- NOITEMS=$(cat "$CONF" | jq -r ".["$i"].files | length")
- j=0
- while [ "$j" -lt "$NOITEMS" ]; do
- # For each file set, obtain which files will be copied and where.
- FSRC=$(cat "$CONF" | jq -r .["$i"].files["$j"].src)
- FDEST=$(cat "$CONF" | jq -r .["$i"].files["$j"].dest)
- # Make the destination directory.
- mkdir -p "$DESTROOT"/"$FDEST"
- echo " ""$FSRC"
- if contains "$FSRC" "\*"; then
- # If a wildcard is used in the file set, copy by file expansion (option -t).
- pushd "$SRCDIR" > /dev/null
- cp -t "$DESTROOT"/"$FDEST" $FSRC
- popd > /dev/null
- else
- # Else, copy normally.
- cp "$SRCDIR"/"$FSRC" "$DESTROOT"/"$FDEST"
- fi
- j=$(($j + 1))
- done
- # Once all the file sets are copied, unmount the disk
- # and delete its associated loop device.
- udisksctl unmount -b "$LOOP" > /dev/null
- udisksctl loop-delete -b "$LOOP"
- i=$(($i + 1))
- done
- ## Test set
- This script was tested with the following disk set: [Microsoft C Compiler 4.0](https://winworldpc.com/download/1ce2809c-2b4c-e280-9804-11c3a6e28094). The first 3 `.img` disks inside the ZIP (`disk01.img`, `disk02.img`, and `disk03.img`) should be placed in the same directory the script is.
- The corresponding JSON recipe used for the test is below. It is also placed in the same directory the script is for convenience.
- ### `steps.json`
- [
- {
- "disk": "disk01.img",
- "files": [
{"src": "*","dest": "bin"}- ]
- },
- {
- "disk": "disk02.img",
- "files": [
{"src": "*.EXE","dest": "bin"}- ]
- },
- {
- "disk": "disk03.img",
- "files": [
{"src": "LINK.EXE","dest": "bin"},{"src": "*.H","dest": "include"},{"src": "SYS/*.H","dest": "include/sys"},{"src": "SLIBC.LIB","dest": "lib"},{"src": "SLIBFP.LIB","dest": "lib"},{"src": "EM.LIB","dest": "lib"},{"src": "LIBH.LIB","dest": "lib"}- ]
- }
- ]
- The test is performed by opening a terminal and executing the following command:
- $ ./imgdisk-copy.sh testing/
- The command will output each disk image name as it is mounted, and under it the names of the files being copied (unexpanded), as follows:
- disk01.img
- *
- disk02.img
- *.EXE
- disk03.img
- LINK.EXE
- *.H
- SYS/*.H
- SLIBC.LIB
- SLIBFP.LIB
- EM.LIB
- LIBH.LIB
- The result will be a directory `testing` under where the script is with the following structure:
- testing/
- ├── bin
- │ ├── C1.EXE
- │ ├── C2.EXE
- │ ├── C3.EXE
- │ ├── CL.EXE
- │ ├── CV.EXE
- │ ├── EXEMOD.EXE
- │ ├── EXEPACK.EXE
- │ ├── LIB.EXE
- │ ├── LINK.EXE
- │ ├── MAKE.EXE
- │ ├── MSC.EXE
- │ └── SETENV.EXE
- ├── include
- │ ├── sys
- │ │ ├── LOCKING.H
- │ │ ├── STAT.H
- │ │ ├── TIMEB.H
- │ │ ├── TYPES.H
- │ │ └── UTIME.H
- │ ├── ASSERT.H
- │ ├── CONIO.H
- │ ├── CTYPE.H
- │ ├── DIRECT.H
- │ ├── DOS.H
- │ ├── ERRNO.H
- │ ├── FCNTL.H
- │ ├── FLOAT.H
- │ ├── IO.H
- │ ├── LIMITS.H
- │ ├── MALLOC.H
- │ ├── MATH.H
- │ ├── MEMORY.H
- │ ├── PROCESS.H
- │ ├── SEARCH.H
- │ ├── SETJMP.H
- │ ├── SHARE.H
- │ ├── SIGNAL.H
- │ ├── STDARG.H
- │ ├── STDDEF.H
- │ ├── STDIO.H
- │ ├── STDLIB.H
- │ ├── STRING.H
- │ ├── TIME.H
- │ ├── V2TOV3.H
- │ └── VARARGS.H
- └── lib
- ├── EM.LIB
- ├── LIBH.LIB
- ├── SLIBC.LIB
- └── SLIBFP.LIB
- _(Brought over from [SE](https://codereview.stackexchange.com/q/209507/98306).)_
- <hr />
- This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs it requires and the test I used so that you can test it too.
- Any comments regarding programming style and improvements are welcome.
- <hr />
- ## Overview
- The following is a Bash shell script that copies files stored inside disk images into a directory in the filesystem.
- The script takes two parameters:
- * The first one is optional and defines a root directory (existing or not) that will contain the files being copied.
- * The second one, optional when the first one is given, is a path to a valid JSON-formatted file that describes:
- 1. which disk images will be opened,
- 2. which files inside each disk image will be copied, and
- 3. which path inside the directory root will be used as the destination for the files being copied.
- The first parameter defaults to the current directory when not given. The second one defaults to a file named `steps.json` located in the current directory. If the first parameter is not given, the second one can't be either.
- ## Prerequisites
- This script requires the following external programs to work correctly:
- * The JSON parsing program `jq`.
- * The disk image manipulation utility `udisksctl`.
- To install these dependencies, use one of the following commands:
- * Ubuntu
- $ sudo apt install jq udisks2
- * Fedora
- $ sudo dnf install jq udisks2
- ## Script
- The complete script is below. It can be marked as executable to avoid having to prepend `bash` to its execution command. There is no restrictions on directories this script may reside into. For the purpose of the test below, the directory where it resides has read/write permissions.
- ### `imgdisk-copy.sh`
- #!/bin/bash
- # Copying files contained inside disk images via JSON recipe.
- # logo_writer
- # December 12th, 2018
- # Is a string contained in another? Return 0 if so; 1 if not.
- # By fjarlq, from https://stackoverflow.com/a/8811800/5397930
- contains() {
- string="$1"
- substring="$2"
- if test "${string#*$substring}" != "$string"; then
- return 0
- else
- return 1
- fi
- }
- # Obtain the absolute path of a given directory.
- # By dogbane, from https://stackoverflow.com/a/3915420
- abspath() {
- dir="$1"
- echo "$(cd "$(dirname "$dir")"; pwd -P)/$(basename "$dir")"
- }
- # The main script starts here.
- # If no first parameter is given, assume current directory.
- if [ -z "$1" ]; then
- DESTROOT="."
- else
- # Omit any trailing slash
- DESTROOT=$(abspath "${1%/}")
- fi
- # If no second parameter is given, assume file "steps.json".
- # If no first parameter is given, this can't be either.
- if [ -z "$2" ]; then
- CONF="./steps.json"
- else
- CONF="$2"
- fi
- # Create the root directory where the files will the put.
- mkdir -p "$DESTROOT"
- # How many disks will be processed?
- LIMIT=$(cat "$CONF" | jq -r length)
- i=0
- while [ "$i" -lt "$LIMIT" ]; do
- # For each disk, get its file name.
- DISK=$(cat "$CONF" | jq -r .["$i"].disk)
- echo "$DISK"
- # Setup a loop device for the disk and get its name.
- RES=$(udisksctl loop-setup -f "$DISK")
- LOOP=$(echo "$RES" | cut -f5 -d' ' | head -c -2)
- # Using the loop device obtained, mount the disk.
- # Obtain the mount root directory afterwards.
- RES=$(udisksctl mount -b "$LOOP")
- SRCDIR=$(echo "$RES" | sed -nE 's|.*at (.*)\.|\1|p')
- # How many file sets will be copied?
- NOITEMS=$(cat "$CONF" | jq -r ".["$i"].files | length")
- j=0
- while [ "$j" -lt "$NOITEMS" ]; do
- # For each file set, obtain which files will be copied and where.
- FSRC=$(cat "$CONF" | jq -r .["$i"].files["$j"].src)
- FDEST=$(cat "$CONF" | jq -r .["$i"].files["$j"].dest)
- # Make the destination directory.
- mkdir -p "$DESTROOT"/"$FDEST"
- echo " ""$FSRC"
- if contains "$FSRC" "\*"; then
- # If a wildcard is used in the file set, copy by file expansion (option -t).
- pushd "$SRCDIR" > /dev/null
- cp -t "$DESTROOT"/"$FDEST" $FSRC
- popd > /dev/null
- else
- # Else, copy normally.
- cp "$SRCDIR"/"$FSRC" "$DESTROOT"/"$FDEST"
- fi
- j=$(($j + 1))
- done
- # Once all the file sets are copied, unmount the disk
- # and delete its associated loop device.
- udisksctl unmount -b "$LOOP" > /dev/null
- udisksctl loop-delete -b "$LOOP"
- i=$(($i + 1))
- done
- ## Test set
- This script was tested with the following disk set: [Microsoft C Compiler 4.0](https://winworldpc.com/download/1ce2809c-2b4c-e280-9804-11c3a6e28094). The first 3 `.img` disks inside the ZIP (`disk01.img`, `disk02.img`, and `disk03.img`) should be placed in the same directory the script is.
- The corresponding JSON recipe used for the test is below. It is also placed in the same directory the script is for convenience.
- ### `steps.json`
- [
- {
- "disk": "disk01.img",
- "files": [
- { "src": "*", "dest": "bin" }
- ]
- },
- {
- "disk": "disk02.img",
- "files": [
- { "src": "*.EXE", "dest": "bin" }
- ]
- },
- {
- "disk": "disk03.img",
- "files": [
- { "src": "LINK.EXE", "dest": "bin" },
- { "src": "*.H", "dest": "include" },
- { "src": "SYS/*.H", "dest": "include/sys" },
- { "src": "SLIBC.LIB", "dest": "lib" },
- { "src": "SLIBFP.LIB", "dest": "lib" },
- { "src": "EM.LIB", "dest": "lib" },
- { "src": "LIBH.LIB", "dest": "lib" }
- ]
- }
- ]
- The test is performed by opening a terminal and executing the following command:
- $ ./imgdisk-copy.sh testing/
- The command will output each disk image name as it is mounted, and under it the names of the files being copied (unexpanded), as follows:
- disk01.img
- *
- disk02.img
- *.EXE
- disk03.img
- LINK.EXE
- *.H
- SYS/*.H
- SLIBC.LIB
- SLIBFP.LIB
- EM.LIB
- LIBH.LIB
- The result will be a directory `testing` under where the script is with the following structure:
- testing/
- ├── bin
- │ ├── C1.EXE
- │ ├── C2.EXE
- │ ├── C3.EXE
- │ ├── CL.EXE
- │ ├── CV.EXE
- │ ├── EXEMOD.EXE
- │ ├── EXEPACK.EXE
- │ ├── LIB.EXE
- │ ├── LINK.EXE
- │ ├── MAKE.EXE
- │ ├── MSC.EXE
- │ └── SETENV.EXE
- ├── include
- │ ├── sys
- │ │ ├── LOCKING.H
- │ │ ├── STAT.H
- │ │ ├── TIMEB.H
- │ │ ├── TYPES.H
- │ │ └── UTIME.H
- │ ├── ASSERT.H
- │ ├── CONIO.H
- │ ├── CTYPE.H
- │ ├── DIRECT.H
- │ ├── DOS.H
- │ ├── ERRNO.H
- │ ├── FCNTL.H
- │ ├── FLOAT.H
- │ ├── IO.H
- │ ├── LIMITS.H
- │ ├── MALLOC.H
- │ ├── MATH.H
- │ ├── MEMORY.H
- │ ├── PROCESS.H
- │ ├── SEARCH.H
- │ ├── SETJMP.H
- │ ├── SHARE.H
- │ ├── SIGNAL.H
- │ ├── STDARG.H
- │ ├── STDDEF.H
- │ ├── STDIO.H
- │ ├── STDLIB.H
- │ ├── STRING.H
- │ ├── TIME.H
- │ ├── V2TOV3.H
- │ └── VARARGS.H
- └── lib
- ├── EM.LIB
- ├── LIBH.LIB
- ├── SLIBC.LIB
- └── SLIBFP.LIB
#1: Initial revision
Serial copying from disk images to folder in Bash
_(Brought over from [SE](https://codereview.stackexchange.com/q/209507/98306).)_ <hr /> This is a Bash script that copies files stored inside disk images to a directory, using a defined structure provided via a JSON file. I've included the external programs it requires and the test I used so that you can test it too. Any comments regarding programming style and improvements are welcome. <hr /> ## Overview The following is a Bash shell script that copies files stored inside disk images into a directory in the filesystem. The script takes two parameters: * The first one is optional and defines a root directory (existing or not) that will contain the files being copied. * The second one, optional when the first one is given, is a path to a valid JSON-formatted file that describes: 1. which disk images will be opened, 2. which files inside each disk image will be copied, and 3. which path inside the directory root will be used as the destination for the files being copied. The first parameter defaults to the current directory when not given. The second one defaults to a file named `steps.json` located in the current directory. If the first parameter is not given, the second one can't be either. ## Prerequisites This script requires the following external programs to work correctly: * The JSON parsing program `jq`. * The disk image manipulation utility `udisksctl`. In Ubuntu, these programs can be installed with the following command: $ sudo apt install jq udisks2 ## Script The complete script is below. It can be marked as executable to avoid having to prepend `bash` to its execution command. There is no restrictions on directories this script may reside into. For the purpose of the test below, the directory where it resides has read/write permissions. ### `imgdisk-copy.sh` #!/bin/bash # Copying files contained inside disk images via JSON recipe. # logo_writer # December 12th, 2018 # Is a string contained in another? Return 0 if so; 1 if not. # By fjarlq, from https://stackoverflow.com/a/8811800/5397930 contains() { string="$1" substring="$2" if test "${string#*$substring}" != "$string"; then return 0 else return 1 fi } # Obtain the absolute path of a given directory. # By dogbane, from https://stackoverflow.com/a/3915420 abspath() { dir="$1" echo "$(cd "$(dirname "$dir")"; pwd -P)/$(basename "$dir")" } # The main script starts here. # If no first parameter is given, assume current directory. if [ -z "$1" ]; then DESTROOT="." else # Omit any trailing slash DESTROOT=$(abspath "${1%/}") fi # If no second parameter is given, assume file "steps.json". # If no first parameter is given, this can't be either. if [ -z "$2" ]; then CONF="./steps.json" else CONF="$2" fi # Create the root directory where the files will the put. mkdir -p "$DESTROOT" # How many disks will be processed? LIMIT=$(cat "$CONF" | jq -r length) i=0 while [ "$i" -lt "$LIMIT" ]; do # For each disk, get its file name. DISK=$(cat "$CONF" | jq -r .["$i"].disk) echo "$DISK" # Setup a loop device for the disk and get its name. RES=$(udisksctl loop-setup -f "$DISK") LOOP=$(echo "$RES" | cut -f5 -d' ' | head -c -2) # Using the loop device obtained, mount the disk. # Obtain the mount root directory afterwards. RES=$(udisksctl mount -b "$LOOP") SRCDIR=$(echo "$RES" | sed -nE 's|.*at (.*)\.|\1|p') # How many file sets will be copied? NOITEMS=$(cat "$CONF" | jq -r ".["$i"].files | length") j=0 while [ "$j" -lt "$NOITEMS" ]; do # For each file set, obtain which files will be copied and where. FSRC=$(cat "$CONF" | jq -r .["$i"].files["$j"].src) FDEST=$(cat "$CONF" | jq -r .["$i"].files["$j"].dest) # Make the destination directory. mkdir -p "$DESTROOT"/"$FDEST" echo " ""$FSRC" if contains "$FSRC" "\*"; then # If a wildcard is used in the file set, copy by file expansion (option -t). pushd "$SRCDIR" > /dev/null cp -t "$DESTROOT"/"$FDEST" $FSRC popd > /dev/null else # Else, copy normally. cp "$SRCDIR"/"$FSRC" "$DESTROOT"/"$FDEST" fi j=$(($j + 1)) done # Once all the file sets are copied, unmount the disk # and delete its associated loop device. udisksctl unmount -b "$LOOP" > /dev/null udisksctl loop-delete -b "$LOOP" i=$(($i + 1)) done ## Test set This script was tested with the following disk set: [Microsoft C Compiler 4.0](https://winworldpc.com/download/1ce2809c-2b4c-e280-9804-11c3a6e28094). The first 3 `.img` disks inside the ZIP (`disk01.img`, `disk02.img`, and `disk03.img`) should be placed in the same directory the script is. The corresponding JSON recipe used for the test is below. It is also placed in the same directory the script is for convenience. ### `steps.json` [ { "disk": "disk01.img", "files": [ { "src": "*", "dest": "bin" } ] }, { "disk": "disk02.img", "files": [ { "src": "*.EXE", "dest": "bin" } ] }, { "disk": "disk03.img", "files": [ { "src": "LINK.EXE", "dest": "bin" }, { "src": "*.H", "dest": "include" }, { "src": "SYS/*.H", "dest": "include/sys" }, { "src": "SLIBC.LIB", "dest": "lib" }, { "src": "SLIBFP.LIB", "dest": "lib" }, { "src": "EM.LIB", "dest": "lib" }, { "src": "LIBH.LIB", "dest": "lib" } ] } ] The test is performed by opening a terminal and executing the following command: $ ./imgdisk-copy.sh testing/ The command will output each disk image name as it is mounted, and under it the names of the files being copied (unexpanded), as follows: disk01.img * disk02.img *.EXE disk03.img LINK.EXE *.H SYS/*.H SLIBC.LIB SLIBFP.LIB EM.LIB LIBH.LIB The result will be a directory `testing` under where the script is with the following structure: testing/ ├── bin │ ├── C1.EXE │ ├── C2.EXE │ ├── C3.EXE │ ├── CL.EXE │ ├── CV.EXE │ ├── EXEMOD.EXE │ ├── EXEPACK.EXE │ ├── LIB.EXE │ ├── LINK.EXE │ ├── MAKE.EXE │ ├── MSC.EXE │ └── SETENV.EXE ├── include │ ├── sys │ │ ├── LOCKING.H │ │ ├── STAT.H │ │ ├── TIMEB.H │ │ ├── TYPES.H │ │ └── UTIME.H │ ├── ASSERT.H │ ├── CONIO.H │ ├── CTYPE.H │ ├── DIRECT.H │ ├── DOS.H │ ├── ERRNO.H │ ├── FCNTL.H │ ├── FLOAT.H │ ├── IO.H │ ├── LIMITS.H │ ├── MALLOC.H │ ├── MATH.H │ ├── MEMORY.H │ ├── PROCESS.H │ ├── SEARCH.H │ ├── SETJMP.H │ ├── SHARE.H │ ├── SIGNAL.H │ ├── STDARG.H │ ├── STDDEF.H │ ├── STDIO.H │ ├── STDLIB.H │ ├── STRING.H │ ├── TIME.H │ ├── V2TOV3.H │ └── VARARGS.H └── lib ├── EM.LIB ├── LIBH.LIB ├── SLIBC.LIB └── SLIBFP.LIB