Home > Mobile >  Reading filename using regexp in Bash
Reading filename using regexp in Bash

Time:05-15

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
  • Related