Ajuda com script Bash - anexando números seqüenciais

6

Eu sou muito novo no bash scripting e espero que alguém me ajude.

Eu tenho pastas que incluem imagens com nomes assim:

file_001.jpeg  
file_002.jpeg  
file_003.jpeg  

Estou tentando escrever uma função bash que aceita dois argumentos e renomeia arquivos assim:

photo-argument1-argument2_001.jpeg  

por exemplo.

photo-christmas-2014_001.jpeg  

Veja o que eu tenho:

function rename () {
  title="photo"
  h="-"
  u="_"
  new=$title$h$1$h$2$u
  for file in *.jpeg; do
    mv -v "$file" "$new"
  done
}

então, executar rename birthday 2015 produz photo-birthday-2015_ , por exemplo.

Há apenas um problema: como adicionar números ao novo nome de arquivo? Retirar os números existentes no nome do arquivo ou gerar novos números seria ótimo no que diz respeito aos resultados, mas qual é a maneira melhor / mais fácil, e como eu faria para que isso acontecesse?

    
por arokath 19.09.2016 / 11:12

4 respostas

8

Você pode conseguir que o bash conte para você apenas dizendo por onde começar, assim:

$ n=0
$ echo $((++n))
1
$ echo $((++n))
2
$ echo $((++n))
3

Você pode usar printf %03d para formatar o resultado de $((++n)) como 001 002 003 e 010 , 011 etc, para uma classificação mais precisa. Além disso, não há nenhum ponto definindo - e _ como variáveis, pois elas não vão variar. Sua função poderia ser assim:

function rename () {
  title="photo"
  n=0
  for file in *.jpeg; do
   printf -v new "$title-$1-$2_%03d.jpeg" "$((++n))"
   mv -v -- "$file" "$new"
  done
}

O que faz:

$ rename birthday 2015
'file_001.jpeg' -> 'photo-birthday-2015_001.jpeg'
'file_002.jpeg' -> 'photo-birthday-2015_002.jpeg'
'file_003.jpeg' -> 'photo-birthday-2015_003.jpeg'

Mas já existe um comando rename útil no Ubuntu, então você pode querer usar um nome diferente:)

    
por Zanna 19.09.2016 / 11:43
3

Alternativa python ligeiramente longa mas utilizável. Supondo que sua nomenclatura seja consistente com o que você tem no exemplo, você poderia usar essa função em ~/.bashrc . (Lembre-se dos caracteres "\". Não deve haver espaço depois disso, somente nova linha)

rename_photos()
{
    python -c 'import os,re,sys; \
    [ os.rename(f, "photo_"+sys.argv[1]+\
      "_"+sys.argv[2]+"_"+re.split("[_.]",f)[-2]+\
      "."+re.split("[_.]",f)[-1])  \
      for f in os.listdir(".") \
    ]' "$1" "$2"
}

E chame como

rename_photos arg1 arg2

Supondo que sua nomenclatura seja consistente, o que isso faz é dividir o nome do arquivo em partes em "." e "_" e renomeia-os via os.rename function

Por exemplo:

$ ls
file_001.jpeg  file_002.jpeg  file_003.jpeg
$ rename_photos birthday 2016
$ ls
photo_birthday_2016_001.jpeg  photo_birthday_2016_002.jpeg  photo_birthday_2016_003.jpeg

Versão do script

Sem torná-lo excessivamente complexo, aqui está um pequeno script que faz a mesma função. Há muitos comentários para explicar o que cada parte faz. O script em si deve ser armazenado em um dos diretórios que pertencem à sua variável $PATH , por exemplo, na sua pasta ~/bin . Caso contrário, ele executa exatamente a mesma função (além de imprimir novos nomes de arquivos)

#!/usr/bin/env python
import os
import re
import sys

# The operates on all files in the current working
# directory, so you would have to cd to your folder
# and run script there. 
for item in os.listdir("."):

    # We don't wanna rename the script itself ( just in case ) and
    # we don't
    if os.path.join("./" + item) != __file__ and \
       os.path.isfile("./" + item):
           title="photo_"

           # Old name can be split into parts using _ and . as 
           # separators, so we only take items between those as one.
           # The last item (-1) is extension, and the one
           # before extension is number
           old_name = re.split("[_.]",item)
           new_name = sys.argv[1] + sys.argv[2] + "_" \
                      + old_name[-2] + "." + old_name[-1]

           print(new_name)
           os.rename(item,new_name)
    
por Sergiy Kolodyazhnyy 19.09.2016 / 14:13
3

O que eu entendi, você só quer adicionar números sequenciais ao final. Eu pessoalmente faria isso

 function rename () {
  count=1           #The first photo will get number 1 to the end
  title="photo"
  h="-"
  u="_"
  new=$title$h$1$h$2$u
  for file in *.jpeg; do
    if [ $count -lt 10 ]; then
        mv -v "$file" "${new}00$count" #numbers 1-9 will be like 001 002..
    elif [ $count -lt 100 ]; then
        mv -v "$file" "${new}0$count" #numbers 10-99 like 022 056 etc..
    else
        mv -v "$file" "$new$count"
    fi
    count=$[ $count + 1 ]      #count variable gets bigger by one 
  done
}

Quando os arquivos forem renomeados, eles obterão números sequenciais com preenchimento até o final. Isso poderia ser feito de forma diferente, como indicado em outras respostas, mas acho isso muito fácil de entender, caso uma pessoa não tenha um conhecimento muito bom sobre scripts de bash

Espero que isso ajude!

    
por jiipeezz 19.09.2016 / 11:35
1

Você pode decidir por si mesmo qual é o caminho mais fácil.

Extraindo números antigos

Você pode obter os números em seu nome de arquivo com um comando como grep:

number=$(egrep -o '[0-9]+' <<< "$file")

O comando acima salva qualquer seqüência de dígitos (correspondidos pelo padrão '[0-9] +') no arquivo variável (passado para grep através de <<< ) para o número da variável.

Gerando novos números

Você pode tentar algo como o abaixo:

number=0 # initialize number to 0
for file in *.jpeg; do
    ... # do some stuff here
    ((number+=1)) # adds 1 to the variable number
done

Isso gera um número a partir de 0 para cada um dos seus arquivos.

Pode ser útil ter números formatados com uma largura fixa (ou seja, 001 em vez de 1) para fins de classificação. Nesse caso, você pode usar printf para obter uma saída desejada:

number_formatted="$(printf "%03d" "$number")"

O código acima formata "12" como "012" e "321" como "321". O "% 03d" especifica o formato (0 significa o prefixo 0 ao número, 3 especifica o total de 3 dígitos impressos, incluindo quaisquer 0s).

    
por anon 19.09.2016 / 11:44