Как переименовать и перезаписать часть имени файла в Bash одновременно? - PullRequest
0 голосов
/ 22 апреля 2020

У меня есть несколько JS файлов в папке, например, foo. js, this_is_foo. js, foo_is_function. js.

Я хочу добавить число, которое передается в качестве параметра перед расширением ". js", например foo.1. js, this_is_foo.1. js, foo_is_function.1. js

Я пишу скрипт для успешного добавления числа в первый раз, но если Я запускаю скрипт дважды, он не перезаписывает первое число, а добавляется сразу после этого.

Фактический результат: foo. js -> foo.1. js (1-й запуск) -> foo.1.2. js (2-й запуск).

Ожидаемый результат: foo. js -> foo.1. js (1-й запуск) -> foo.2. js (2-й запуск).

Это мой скрипт:

#!/bin/sh
param=$1
for file in *.js; do
    ext="${file##*.}";
    filename="${file%.*}";
    mv "$file" "${filename}.${param}.${ext}";
done

Как я могу это сделать? Я хочу написать чистый bash скрипт, не использовать никаких инструментов.

Ответы [ 4 ]

1 голос
/ 22 апреля 2020

Вы можете использовать расширенную глобализацию, чтобы сопоставить необязательный . (тот, что перед номером) и любое количество цифр перед суффиксом .js.

Я также добавил . к $param переменная, если переменная не пустая. Таким образом, вы можете вызывать скрипт без параметра, и .<number> удаляется вместо добавления / изменения.

#!/bin/bash

shopt -s extglob # enable extended globbing

param=$1
if [ -n "$param" ]; then
    param=.${param} # add prefix `.`
fi

for file in *.js; do
    newfile=${file%%?(.)*([0-9]).js}${param}.js
    if [ "$file" = "$newfile" ]; then
        echo "skipping \"${file}\", no need to rename"
    elif [ -f "$newfile" ]; then
        echo "skipping \"$file\", file \"$newfile\" already exists"
    else
        mv "$file" "$newfile"
    fi
done

Использование:

./script.sh 1 # change suffix to `.1.js`
./script.sh 2 # change suffix to `.2.js`
./script.sh   # change suffix to `.js`
1 голос
/ 22 апреля 2020

Перед выполнением переименования вы можете проверить, что после последней точки в имени файла (${filename%.*}) указано число c. Если это так, переключите это с параметром вместо добавления нового параметра

Поскольку вы пишете, что хотите использовать чистый bash Я предполагаю, что можно изменить шебанг на #!/bin/bash:

#!/bin/bash
param=$1
for file in *.js; do
    ext="${file##*.}";
    filename="${file%.*}";

    # Check if what is after the last dot in filename is numeric
    # Then assume that it should be switched to param
    if [[ ${filename##*.} =~ ^[0-9]+$ ]]; then
        mv "$file" "${filename%.*}.${param}.${ext}"

    ## Else add param
    else
        mv "$file" "${filename}.${param}.${ext}"
    fi  
done

Testrun

$> touch a.js && find -type f -name *.js && \
 ./test.sh 1 && find -type f -name *.js && \
 ./test.sh 2 && find -type f -name *.js

./a.js
./a.1.js
./a.2.js
0 голосов
/ 23 апреля 2020

Это может делать то, что вы хотите.

#!/usr/bin/env bash

counter=1

for file in *.js; do
  if [[ $file =~ (^[^\.]+)(\.js)$ ]]; then
    mv -v "$file" "${BASH_REMATCH[1]}.$counter${BASH_REMATCH[2]}"
  elif [[ $file =~ (^[^\.]+)\.([[:digit:]]+)(\.js)$ ]]; then
    first=${BASH_REMATCH[1]}
    counter=${BASH_REMATCH[2]}
    extension=${BASH_REMATCH[3]}
    ((counter++))
    mv -v "$file" "$first.$counter$extension"
  fi
done

В действии.

mkdir -p /tmp/123 && cd /tmp/123
touch foo.js
touch this_is_foo.js
touch this_is_foucntion.js

Первый запуск

./myscript

Вывод

renamed 'foo.js' -> 'foo.1.js'
renamed 'this_is_foo.js' -> 'this_is_foo.1.js'
renamed 'this_is_foucntion.js' -> 'this_is_foucntion.1.js'

Второй запуск.

renamed 'foo.1.js' -> 'foo.2.js'
renamed 'this_is_foo.1.js' -> 'this_is_foo.2.js'
renamed 'this_is_foucntion.1.js' -> 'this_is_foucntion.2.js'

Третий запуск.

renamed 'foo.2.js' -> 'foo.3.js'
renamed 'this_is_foo.2.js' -> 'this_is_foo.3.js'
renamed 'this_is_foucntion.2.js' -> 'this_is_foucntion.3.js'

Использование for loop

for i in {1..5}; do ./script.sh ; done

Вывод

renamed 'foo.js' -> 'foo.1.js'
renamed 'this_is_foo.js' -> 'this_is_foo.1.js'
renamed 'this_is_foucntion.js' -> 'this_is_foucntion.1.js'
renamed 'foo.1.js' -> 'foo.2.js'
renamed 'this_is_foo.1.js' -> 'this_is_foo.2.js'
renamed 'this_is_foucntion.1.js' -> 'this_is_foucntion.2.js'
renamed 'foo.2.js' -> 'foo.3.js'
renamed 'this_is_foo.2.js' -> 'this_is_foo.3.js'
renamed 'this_is_foucntion.2.js' -> 'this_is_foucntion.3.js'
renamed 'foo.3.js' -> 'foo.4.js'
renamed 'this_is_foo.3.js' -> 'this_is_foo.4.js'
renamed 'this_is_foucntion.3.js' -> 'this_is_foucntion.4.js'
renamed 'foo.4.js' -> 'foo.5.js'
renamed 'this_is_foo.4.js' -> 'this_is_foo.5.js'
renamed 'this_is_foucntion.4.js' -> 'this_is_foucntion.5.js'
0 голосов
/ 22 апреля 2020

Posix-совместимое решение, которое позволяет вам продолжать использовать /bin/sh

#!/bin/sh
param=$1
for file in *.js; do
    ext="${file##*.}";
    filename="${file%.*}";
    [ -z "${filename##*.##*[!0-9]*}" ] && mv "$file" "${filename}.${param}.${ext}" || mv "$file" "${filename%.*}.${param}.${ext}"
done

Testrun

$> touch a.js && find -type f -name *.js && \
 ./test.sh 1 && find -type f -name *.js && \
 ./test.sh 2 && find -type f -name *.js

./a.js
./a.1.js
./a.2.js
...