Чтение имени файла с использованием регулярного выражения в Bash

Я пишу bash-скрипт, который вызывает внешнюю программу, которая генерирует zip-файл в форме ########.zip, в котором '#'s# может быть любой десятичной цифрой. Невозможно предсказать, какими будут цифры.

До сих пор мне удавалось использовать регулярное выражение [0-9][0-9]*zip для таких вещей, как перемещение zip-файла и его распаковка. Однако теперь мне нужно добавить в архив txt-файл под именем каталога ########, где цифры совпадают с именем архива. Итак, если архив 12345678.zip, мне нужно добавить файл 12345678/foo.txt.

Единственный способ сделать это, как я вижу, - создать каталог «12345678» и скопировать туда файл, а затем добавить каталог в архив. Однако я не могу понять, как получить имя архива, чтобы создать каталог.

Лучшее, что я мог сделать, это использовать обратные кавычки, чтобы назначить вывод ls -l переменной, а затем проанализировать это, чтобы получить только часть имени файла. Но должен же быть более простой способ?

Я использую 7z в качестве утилиты zip, если это имеет значение.

Спасибо!

🤔 А знаете ли вы, что...
С Bash можно создавать скрипты, которые мониторят системные ресурсы и производительность.


50
2

Ответы:

Решено

То, что вы просите, - это не регулярное выражение, а «глобальное выражение». В частности, если вы хотите сопоставить любое количество цифр, это можно сделать с помощью функции bash, называемой расширенным подстановкой или «extglobs». Подробнее читайте на странице 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

В расширение параметраdigits=${f%.zip} мы убираем .zip с конца имени файла и сохраняем остальное в переменной digits.


Расширение вышеизложенного для работы во временном каталоге и очистки после себя:

#!/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

Поскольку OP использует 7z, мы можем использовать опцию rn для переименования файла в архиве и, чтобы исключить необходимость создания/удаления временного подкаталога...

Настраивать:

$ '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

Создайте/заполните ${zipfile}sample.txt и 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

Теперь добавьте каталог ${digits} в качестве префикса к 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