[[... ]]
токенизация конфликтует с регулярными выражениями (подробнее об этом в мой ответ на ваш следующий -вопрос вверх)и \
перегружен как оператор кавычек оболочки и оператор регулярного выражения (с некоторые помехи между ними в bash ), и даже когда нет очевидной причины для конфликта, поведение может быть неожиданным. Правила могут сбивать с толку.
Кто может сказать, что они будут делать, не попробовав (на всех возможных входных данных )с любой данной версией bash
?
[[ $a = a|b ]]
[[ $a =~ a|b ]]
[[ $a =~ a&b ]]
[[ $a =~ (a|b) ]]
[[ $a =~ ([)}]*) ]]
[[ $a =~ [/\(] ]]
[[ $a =~ \s+ ]]
[[ $a =~ ( ) ]]
[[ $a =~ [ ] ]]
[[ $a =~ ([ ]) ]]
Вы не можете заключать регулярные выражения в кавычки, потому что если вы это сделаете, начиная с bash 3.2 и если совместимость с bash 3.1 не включена, цитирование регулярных выражений удаляет особое значение оператора RE. Например,
[[ $a =~ 'a|b' ]]
Соответствует, если $a
содержит только литерал a|b
.
Сохранение регулярного выражения в переменной позволяет избежать всех этих проблем, а также делает код совместимым с ksh93
иzsh
(при условии, что вы ограничиваетесь POSIX ERE):
regexp='a|b'
[[ $a =~ $regexp ]] # $regexp should *not* be quoted.
В синтаксическом анализе/разметке этой команды оболочки нет двусмысленности, а используемое регулярное выражение хранится в переменной без какого-либо преобразования.
Вот рекурсивный подход, который не требует от вас заранее знать имена файлов tar-архивов. Поместите файл в каталог, в котором больше ничего нет. Затем, предполагая, что все tar-архивы, содержащиеся в родительском архиве, имеют расширение .tar
, вы можете просто выполнить:
file=(*tar); while [[ -e $file ]]; do tar xf "$file"; rm "$file"; file=(*tar); done
file=(*tar);
:установите переменную $file
так, чтобы она содержала имя файла. Должен быть только один файл, соответствующий глобусу *tar
в каталоге, в котором вы его запускаете. while [[ -e $file ]]; do
:пока $file
существует... tar xf $file; rm "$file"; file=(*tar);
:разархивируйте текущее значение $file
, затем удалите только что извлеченный tar-архив и, наконец, установите переменную $file
на имя нового, пока единственного, tar-файла в каталоге. А вот еще более прямой подход(спасибо @kusalananda!). Я сделал архив tar
с помощью этих команд:
$ cat file
This is the text!
$ file=file; for i in {1..1000}; do tar cf $i.tar $file; file=$i.tar; done
Итак, это файл с именем file
, который содержит текст This is the text!\n
. file
был смолен 1000 раз, и теперь у нас есть 1000.tar
. Мы можем распечатать исходный текст с помощью:
$ awk -F'\0' '/[^\0]/{print $(NF)}' 1000.tar
This is the text!
Обратите внимание, что на самом деле это не оригинальный текст. Исходная новая строка была съедена tar
, но заменена на awk
. Чтобы получить реальное значение из архива, вам нужно (последнее $
вот моя подсказка, новой строки не было):
$ awk -F'\0' '/[^\0]/{printf "%s", $NF}' 1000.tar
This is the text!$
В этом конкретном случае я также смог воссоздать имя файла, сказав awk
напечатать последнее поле ($NF
),и 438-е поле перед последним:
awk -F'\0' '/[^\0]/{print $(NF) >$(NF-438)}' 1000.tar
Это создало новый file
с содержимым оригинала. То же самое, что извлечение. Однако я не знаю, является ли -428
магическим числом. tar
, по-видимому, добавляет в свой архив несколько NULL, поэтому я обнаружил это, запустив:
$ awk -F'\0' '{for(i=1;i<=NF;i++){ if($i ~ /file/){print i,NF-i}}}' 1000.tar
434674 438
Это подсказало мне, что поле 434674 имеет содержимое file
, а это 438 полей до последнего.
Если ваш awk
поддерживает gsub
, вы, вероятно, можете сделать его более общим с помощью:
awk -F'\0' '/[^\0]/{gsub(/\0+/,"\0"); print $NF > $(NF-11)}' 1000.tar
Этот простой bash
цикл for должен делать то, что вам нужно:
for i in {1000..1}; do tar -xf $i.tar; done