desenv-web-rp.com

Por que os nomes das minhas pastas acabaram assim e como posso corrigir isso usando um script?

Desculpe se isso tiver uma resposta em outro lugar, não faço idéia de como procurar pelo meu problema.

Eu estava executando algumas simulações em um servidor HPC redhat linux, e meu código para lidar com a estrutura de pastas para salvar a saída teve um bug infeliz. Meu código matlab para criar a pasta era:

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

onde sp.run_number era um número inteiro. Eu esqueci de convertê-lo em uma string, mas por algum motivo, a execução de mkdir(folder); (no matlab) ainda conseguiu. De fato, as simulações foram executadas sem problemas e os dados foram salvos no diretório correspondente.

Agora, quando a estrutura da pasta é consultada/impressa, recebo as seguintes situações:

  • Quando tento tabular o preenchimento automático: run_ run_^A/ run_^B/ run_^C/ run_^D/ run_^E/ run_^F/ run_^G/ run_^H/ run_^I/
  • Quando eu uso ls: run_ run_? run_? run_? run_? run_? run_? run_? run_? run_? run_?.
  • Quando transfiro para o meu Mac usando o rsync, a opção --progress Mostra: run_\#003/ Etc. com (presumo) o número correspondente ao número inteiro em sp.run_number Preenchido com três dígitos; A 10ª execução é run_\#010/
  • Quando visualizo as pastas no Finder, vejo run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
  • Olhando para this question e usando o comando ls | LC_ALL=C sed -n l, Recebo:
run_$
run_\001$
run_\002$
run_\003$
run_\004$
run_\005$
run_\006$
run_\a$
run_\b$
run_\t$
run_$

Não consigo gerenciar cd nas pastas usando qualquer uma dessas representações.

Eu tenho milhares dessas pastas, então precisarei corrigir isso com um script. Qual dessas opções é a representação correta da pasta? Como posso me referir programaticamente a essas pastas para renomeá-las com um nome formatado corretamente usando um script bash? E acho que por uma questão de curiosidade, como diabos isso aconteceu em primeiro lugar?

15
Phill

Você pode usar o utilitário Perl rename (também conhecido como prename ou file-rename) Para renomear os diretórios.

NOTA: Isso não deve ser confundido com rename de util-linux Ou com qualquer outra versão.

rename -n 's/([[:cntrl:]])/ord($1)/eg' run_*/

Isso usa a função ord() do Perl para substituir cada caractere de controle no nome do arquivo pelo número ordinal para esse caractere. por exemplo, ^A se torna 1, ^B se torna 2, etc.

A opção -n É uma execução a seco para mostrar o que renamefaria se você permitir. Remova-o (ou substitua-o por -v Para obter uma saída detalhada) para renomear.

O modificador e na operação s/LHS/RHS/eg Faz com que o Perl execute o RHS (a substituição) como código Perl, e o $1 São os dados correspondentes (o caractere de controle) do LHS.

Se você quiser números preenchidos com zero nos nomes dos arquivos, poderá combinar ord() com sprintf(). por exemplo.

$ rename -n 's/([[:cntrl:]])/sprintf("%02i",ord($1))/eg' run_*/ | sed -n l
rename(run_\001, run_01)$
rename(run_\002, run_02)$
rename(run_\003, run_03)$
rename(run_\004, run_04)$
rename(run_\005, run_05)$
rename(run_\006, run_06)$
rename(run_\a, run_07)$
rename(run_\b, run_08)$
rename(run_\t, run_09)$

Os exemplos acima funcionam se e somente sesp.run_number No seu script matlab estava no intervalo de 0 a 26 (portanto, produziu caracteres de controle nos nomes de diretório).

Para lidar com QUALQUER caractere de 1 byte (ou seja, de 0 a 255), você usaria:

rename -n 's/run_(.)/sprintf("run_%03i",ord($1))/e' run_*/

Se sp.run_number Pudesse ser> 255, você teria que usar a função unpack() do Perl em vez de ord(). Não sei exatamente como o matlab gera um int não convertido em uma string, então você terá que experimentar. Veja perldoc -f unpack Para detalhes.

por exemplo. o seguinte descompacta os valores não assinados de 8 e 16 bits e coloca-os em zero para 5 dígitos de largura:

 rename -n 's/run_(.*)/sprintf("run_%05i",unpack("SC",$1))/e' run_*/
26
cas

E eu acho que por uma questão de curiosidade, como diabos isso aconteceu em primeiro lugar?

folder = [sp.saveLocation, 'run_', sp.run_number, '/'];

onde sp.run_number era um número inteiro. Esqueci de convertê-lo em uma string, mas por algum motivo executando mkdir(folder); (no matlab) ainda conseguiu.

Portanto, parece que mkdir([...]) no Matlab concatena os membros da matriz para criar o nome do arquivo como uma string. Mas você deu um número a ele, e os números são o que os caracteres de um computador realmente são. Portanto, quando sp.run_number Era 1, Fornecia o caractere com valor 1 E, em seguida, o caractere com valor 2, Etc.

Esses são caracteres de controle, não possuem símbolos imprimíveis e imprimi-los em um terminal teria outras consequências. Então, em vez disso, eles geralmente são representados por diferentes tipos de escapadas: \001 (Octal), \x01 (Hex), ^A São representações comuns para o personagem com valor 1. O caractere com valor zero é um pouco diferente, é o byte NUL usado para marcar o final de uma string em C e nas chamadas do sistema Unix.

Se você ultrapassasse 31, começaria a ver caracteres imprimíveis, 32 é espaço (embora não muito visível), 33 = !, 34 = " Etc.

Assim,

  • run_ run_^A/ run_^B/ - O primeiro run_ Corresponde àquele com um byte zero, a string termina aí. Os outros mostram que seu Shell gosta de usar os códigos de controle com ^A. A notação também sugere que o caractere com valor numérico 1 pode ser inserido como Ctrl-A, embora você precise instruir o Shell a interpretar não como um caractere de controle, mas como um literal, Ctrl-VCtrl-A deve fazer isso pelo menos no Bash.

  • ls: run_ run_? run_? - ls não gosta de imprimir caracteres não imprimíveis no terminal, mas os substitui por pontos de interrogação.

  • rsync: run_\#003/ - esse é novo para mim, mas a ideia é a mesma, a barra invertida marca uma fuga e o restante é o valor numérico do personagem. Parece-me que o número aqui está em octal, como no mais comum \003.

  • usando o comando ls | LC_ALL=C sed -n l ... run_\006$run_\a$run_\b$run_\t$ - \a, \b e \t são escapes em C para alarme (campainha), backspace e tab, respectivamente. Eles têm os valores numéricos 7, 8 e 9, portanto, deve ficar claro por que eles vêm depois de \006. Usar esses escapes C é mais uma maneira de marcar os caracteres de controle. Os cifrões à direita marcam o final da linha.

Quanto a cd, supondo que minhas suposições estejam corretas, cd run_ Deve ir para esse único diretório sem um caractere final ímpar e cd run_? Deve gerar um erro, pois o ponto de interrogação é um caractere glob que corresponde a qualquer caractere único e há vários nomes de arquivos correspondentes, mas cd espera apenas um.

Qual dessas opções é a representação correta da pasta?

Todos eles, em certo sentido ...

No Bash, você pode usar as teclas \000 E \x00 Dentro das aspas $'...' Para representar os caracteres especiais, então $'run_\033 (Octal) ou $'run_\x1b' correspondem ao diretório com o valor de caractere 27 (que passa a ser ESC). (Eu não acho que o Bash suporta escapes com números decimais.)

a resposta de cas tem um script para renomeá-los, então não vou lá.

11
ilkkachu

O mais fácil seria criar o nome do arquivo errado e o nome do arquivo correto no mesmo ambiente em que o acidente ocorreu e, em seguida, basta mover/renomear as pastas para os nomes corretos.

Para evitar colisões entre nomes existentes, use melhor outra pasta de destino.

./saveLocationA/wrongname1 -> ./saveLocationB/correctname1
./saveLocationA/wrongname2 -> ./saveLocationB/correctname2
./saveLocationA/wrongname3 -> ./saveLocationB/correctname3

Se possível, eu preferiria corrigir o script e apenas executá-lo novamente; corrigir alguns erros post mortem estranhos provavelmente custa mais e pode introduzir novos problemas.

Boa sorte!

3
Peter