I am writing a bash script that calls an external program which generates a zip file of the form ########.zip which the '#'s# can be any decimal digit. There is no way to predict what the digits will be.
So far I have been able to get by using the regexp [0-9][0-9]*zip for things like moving the zip file around and unzipping it. However, now I need to add a txt file to the archive under the directory name ######## where the digits are the same as the archive name. So, if the archive is 12345678.zip, I need to add the file 12345678/foo.txt.
The only way I can see to do this is to create the directory '12345678' and copy the file there and then add the directory to the archive. However I can't figure out how to get the name of the archive so that I can create the directory.
The best I could some up with was to use backticks to assign the output of ls -l to a variable and then parse that to get just the filename part. But there has to be an easier way?
I am using 7z as the zip utility if it matters.
Thanks!
CodePudding user response:
What you're asking for is not a regex but a "glob expression". In particular, if you want to match any number of digits, this can be done with a bash feature called extended globbing, or "extglobs". Read more at https://wiki.bash-hackers.org/syntax/pattern#extended_pattern_language.
#!/usr/bin/env bash
# ^^^^- NOT sh
shopt -s extglob
for f in ([[:digit:]]).zip; do
digits=${f%.zip}
mkdir -p "$digits"
echo hello >"$digits/foo.txt"
zip "$f" "$digits/foo.txt"
done
In the parameter expansion digits=${f%.zip}
, we take .zip
off the end of the filename, and store the rest in the variable digits
.
Extending the above to work in a temporary directory and clean up after ourselves:
#!/usr/bin/env bash
# ^^^^- NOT sh
shopt -s extglob
olddir=$PWD
for f in ([[:digit:]]).zip; do
digits=${f%.zip}
tempdir="$(mktemp -d -t zipupdate.XXXXXX)"
(
cd "$tempdir" || exit
mkdir -p "$digits" || exit
echo hello >"$digits/foo.txt" || exit
zip "$olddir/$f" "$digits/foo.txt"
)
rm -rf "$tempdir"
done
CodePudding user response:
Since OP is using 7z
we can make use of the rn
option to rename a file within the archive and eliminate the need to create/delete a temporary subdirectory ...
Setup:
$ 'rm' -rf zipdir
$ mkdir zipdir
$ cd zipdir
$ zipfile='12345678.zip'
$ digits="${zipfile//.zip/}"
$ declare -p digits
declare -- digits="12345678"
$ echo abc > sample.txt
$ echo def > foo.txt
Create/populate ${zipfile}
with sample.txt
and foo.txt
:
$ 7z a "${zipfile}" sample.txt foo.txt
... snip ...
Archive size: 158 bytes (1 KiB)
Everything is Ok
$ 7z l "${zipfile}"
... snip ...
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2022-05-14 15:53:16 ..... 4 4 foo.txt
2022-05-14 15:53:16 ..... 4 4 sample.txt
------------------- ----- ------------ ------------ ------------------------
2022-05-14 15:53:16 8 8 2 files
Now add the ${digits}
directory as a prefix to foo.txt
:
$ 7z -- rn "${zipfile}" foo.txt "${digits}/foo.txt"
... snip ...
Archive size: 306 bytes (1 KiB)
Everything is Ok
$ 7z l "${zipfile}"
... snip ...
Date Time Attr Size Compressed Name
------------------- ----- ------------ ------------ ------------------------
2022-05-14 15:53:16 ..... 4 4 12345678/foo.txt
2022-05-14 15:53:16 ..... 4 4 sample.txt
------------------- ----- ------------ ------------ ------------------------
2022-05-14 15:53:16 8 8 2 files