Desculpe se isso tiver uma resposta em outro lugar, não tenho ideia de como procurar meu problema.
Eu estava executando algumas simulações em um servidor HPC linux redhat, e meu código para manipular a estrutura de pastas para salvar a saída teve um erro infeliz. Meu código matlab para criar a pasta foi:
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 a execução mkdir(folder);
(no matlab) ainda foi bem-sucedida. Na verdade, as simulações foram executadas sem problemas e os dados foram salvos no diretório correspondente.
Agora, quando a estrutura de pastas é consultada/impressa, recebo as seguintes situações:
- Quando tento tab autocomplete:
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 eu transfiro para o meu mac usando o rsync, a
--progress
opção mostra:run_\#003/
etc. com (suponho) o número correspondente ao inteirosp.run_number
preenchido com três dígitos, então a 10ª execução érun_\#010/
- Quando vejo as pastas no localizador, vejo
run_ run_ run_ run_ run_ run_ run_ run_ run_ run_?
- Olhando para esta pergunta 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 cd
entrar nas pastas usando nenhuma dessas representações.
Eu tenho milhares dessas pastas, então vou precisar corrigir isso com um script. Qual destas 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 eu acho que por curiosidade, como diabos isso aconteceu em primeiro lugar?
rename
Você pode usar o utilitário perl (também conhecidoprename
comofile-rename
) para renomear os diretórios.NOTA: Isso não deve ser confundido com
rename
fromutil-linux
, ou qualquer outra versão.Isso usa a
ord()
função do perl para substituir cada caractere de controle no nome do arquivo pelo número ordinal desse caractere. por exemplo^A
, torna-se 1,^B
torna-se 2, etc.A
-n
opção é fazer uma simulação para mostrar orename
que faria se você deixasse. Remova-o (ou substitua-o-v
por uma saída detalhada) para realmente renomear.O
e
modificador nas/LHS/RHS/eg
operação faz com que o perl execute o RHS (a substituição) como código perl, e$1
são os dados correspondentes (o caractere de controle) do LHS.Se você quiser números preenchidos com zeros nos nomes dos arquivos, você pode combinar
ord()
comsprintf()
. por exemploOs exemplos acima funcionam se e somente se
sp.run_number
em seu script matlab estiver no intervalo de 0..26 (portanto, produziu caracteres de controle nos nomes dos diretórios).Para lidar com QUALQUER caractere de 1 byte (ou seja, de 0..255), você usaria:
Se
sp.run_number
pudesse ser > 255, você teria que usar aunpack()
função do perl em vez deord()
. Eu não sei exatamente como o matlab produz um int não convertido em uma string, então você terá que experimentar. Vejaperldoc -f unpack
para detalhes.por exemplo, o seguinte irá descompactar valores não assinados de 8 bits e 16 bits e zerá-los para 5 dígitos de largura:
Então, parece que
mkdir([...])
no Matlab concatena os membros do array para construir o nome do arquivo como uma string. Mas, em vez disso, você deu um número, e os números são o que os caracteres em um computador realmente são. Então, quandosp.run_number
era1
, ele dava o caractere com valor1
, e depois o caractere com valor2
, etc.Esses são caracteres de controle, eles não têm 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 escapes:
\001
(octal),\x01
(hex),^A
são todas representações comuns para o caractere com valor1
. O caractere com valor zero é um pouco diferente, é o byte NUL que é usado para marcar o fim de uma string em C e nas chamadas do sistema Unix.Se você for superior a 31, começará a ver caracteres imprimíveis, 32 é espaço (não muito visível), 33 =
!
, 34 ="
etc.Então,
run_ run_^A/ run_^B/
— O primeirorun_
corresponde àquele com um byte zero, a string termina aí. Os outros mostram que seu shell gosta de usar exibir os códigos de controle com^A
. A notação também sugere o fato de que o caractere com valor numérico 1 pode ser inserido como Ctrl-A, embora você precise dizer ao shell para interpretar não como um caractere de controle, mas como um literal, Ctrl-V Ctrl-Adeve fazer isso pelo menos no Bash.ls:
run_ run_? run_?
—ls
não gosta de imprimir caracteres não imprimíveis no terminal, substitui-os por pontos de interrogação.rsync:
run_\#003/
— esse é novo para mim, mas a ideia é a mesma, a barra invertida marca um escape, e o resto é o valor numérico do caractere. 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
C escapa para alarme (campainha), backspace e tab, respectivamente. Eles têm os valores numéricos 7, 8 e 9, então deve ficar claro por que eles vêm depois de\006
. Usar esses escapes C é outra maneira de marcar os caracteres de controle. Os cifrões à direita marcam as extremidades da linha.Quanto a
cd
, supondo que minhas suposições estejam corretas,cd run_
deve ir para aquele único diretório sem um caractere final estranho ecd run_?
deve dar um erro, pois o ponto de interrogação é um caractere glob que corresponde a qualquer caractere único e existem vários nomes de arquivos correspondentes, mascd
apenas espera um.Todos eles, de certa forma...
No Bash, você pode usar os escapes
\000
e entre aspas para representar os caracteres especiais, então (octal) ou corresponder ao diretório com o valor do caractere 27 (que por acaso é ESC). (Acho que o Bash não suporta escapes com números decimais.)\x00
$'...'
$'run_\033
$'run_\x1b'
a resposta de cas tem um script para renomeá-los, então não vou lá.
O mais fácil seria criar o nome de arquivo errado e o nome de arquivo correto no mesmo ambiente em que o acidente aconteceu e, em seguida, basta mover/renomear as pastas para os nomes corretos.
Para evitar colisões entre nomes existentes, é melhor usar outra pasta de destino.
Se possível, prefiro corrigir o script e executá-lo novamente; corrigir algum bug estranho post mortem provavelmente custa mais e pode introduzir novos problemas.
Boa sorte!