#bash #shell
#bash #оболочка
Вопрос:
Есть ли способ переименовать каталог, полный файлов, названных в соответствии со следующим соглашением, без использования регулярных выражений? Например, у меня есть файлы с именами 1.json
, 2.json
, 3.json
, 4.json
и я хочу, чтобы все они были переименованы в их текущие #{NUM}
#{NUM - 1}
, чтобы результирующий набор был: 0.json
, 1.json
, 2.json
, 3.json
.
Используя соглашение:
for i in *.json; do mv -- "$i" ..
Возможно ли это сделать без регулярных выражений? Или я застрял при анализе имени файла, преобразовании строки в целое число и переходе оттуда?
Комментарии:
1. вы показываете только имена файлов с однозначными цифрами, не могли бы вы также иметь имена файлов с 2-, 3-, более-? цифры?
2. @markp-fuso да, и я только что увидел ваш комментарий ниже, чтобы понять, почему это актуально. Я просто опустил их для краткости, но вижу проблему в этом.
Ответ №1:
${var%suffix}
удалит завершающий суффикс. Вы можете использовать его для удаления .json
и получения только чисел.
for file in *.json; do
i="${file%.json}"
echo mv -- "$i".json "$((i-1))".json
done
Удалите echo
, если это выглядит хорошо.
Обратите внимание, что это будет обрабатывать только однозначные имена файлов. Для обработки многозначных имен файлов нам нужно, чтобы они были отсортированы естественным образом, а не лексикографически. Лексикографическая сортировка ставит 10
перед 9
, поскольку символ 1
меньше 9
, чем , что означает 10.json
, что он будет переименован 9.json
до 9.json
переименования 8.json
. Естественная сортировка, напротив, будет сортироваться 9
раньше 10
.
К сожалению, это делает все это в десять раз более загадочным. Глобусы не могут быть отсортированы в строке, поэтому нам приходится перемещать вещи, чтобы мы могли передавать список имен файлов sort -g
. Затем, чтобы перебрать поток имен файлов, мы должны перейти от for
цикла к while read
циклу с заменой процесса.
Базовая структура скелета выглядит следующим образом:
while read file; do
...
done < <(ls *.json | sort -g)
Затем мы добавим несколько улучшений:
- Используйте
while IFS= read -r
, чтобы сделать синтаксический анализ более надежным. - Избегайте синтаксического
ls
анализа, переключившись наprintf
метод на основе a для печати имен файлов. - Используйте разделители NUL вместо новых строк, поскольку новые строки являются технически допустимыми символами в именах файлов. Это означает добавление
printf
,-z
tosort
и-d $''
toread
, чтобы каждый из трех выдавал и потреблял NUL.
Эти шаги являются хорошими общими привычками, но я признаю, что они не очень важны для данного конкретного скрипта, и они делают код похожим на монстра Франкенштейна. Я показываю их здесь в педагогических целях. Я не скажу, удалите ли вы их из своего одноразового скрипта личного использования.
Окончательное, надежное решение:
while IFS= read -rd $'' file; do
i="${file%.json}"
echo mv -- "$i".json "$((i-1))".json
done < <(printf '%s' *.json | sort -zg)
Комментарии:
1. все еще есть возможность перезаписи, если существуют такие имена файлов, как «011,json» и «11.json». Кроме того, вы получите ошибки, если попытаетесь сделать
$((i-1))
, когда i `082″ или что-то в этом роде. 😉2. Это обработает недопустимые восьмеричные числа и выведет новое число с тем же заполнением нуля, что и исходное:
wid=${#i}; new=$(printf "%0*d.json" "$wid" $((10#$i - 1)) ); mv -- "$f" "$new"
— хотя оно переименует «1000.json» в «0999.json» (if
потребуется дополнительное)
Ответ №2:
Вы можете использовать это awk
основанное на этом решение:
printf '%sn' [1-9]*.json | sort -n |
awk -F. '{print "mv", $0, ($1-1 FS $2)}' | bash
mv 1.json 0.json
mv 2.json 1.json
mv 3.json 2.json
mv 4.json 3.json
mv 5.json 4.json
Как только вы будете довольны результатом, вы можете удалить echo
его раньше mv
.
Ответ №3:
попробуйте этот код. simpy на -1 от имени файла. но если ваше имя файла содержит ноль в первом имени, допустим 001.json
..n тогда есть 1.json
, этот код не будет работать. потому что это заменит текущий 1.json
файл
declare -i newName=0
for i in `ls | sort -n | grep ".json"`
do
newName=${i%%.*}-1
mv -- "$i" "$newName.json"
done
Комментарии:
1. в for я думаю, вы можете выполнить сортировку по изменению этого для i в
ls | sort -n | grep ".json"
2. это не удается для имени файла, подобного
082.json
. также перезапись все еще возможна, если имена файлов, такие как «011.json» и «11.json», существуют вместе.3. Пожалуйста, обратите внимание: почему бы не выполнить синтаксический
ls
анализ?