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
estava um número inteiro. Esqueci de convertê-lo em uma string, mas por algum motivo a execução mkdir(folder);
(no matlab) ainda teve êxito. 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
--progress
opção mostra:run_\#003/
etc. com (presumo) o número que corresponde ao número inteirosp.run_number
preenchido com três dígitos, portanto a 10ª execução érun_\#010/
- Quando visualizo 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 acessar cd
as pastas usando nenhuma 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 referenciar programaticamente 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?
fonte
^A
não é literalmente^
seguido porA
, mas Ctrl-A (você pode digitar usando Ctrl-V Ctrl-A, pois Ctrl-A geralmente é um atalho para o shell).run_
e eu tenho que digitar algo/
. Qualquer outro caractere é válido, incluindo caracteres de controle. Não sei o que o matlab teria feito se sp.run_number fosse 0 (provavelmente abortar com um erro ou produzirrun_
, pois o byte NUL encerraria a string do nome do diretório). Obviamente, isso também seria problemático para valores de 16 bits (ou superiores) que continham um byte NUL e também variaria de acordo com a capacidade de endereçamento do sistema executando o matlab.Respostas:
Você pode usar o
rename
utilitário perl (akaprename
oufile-rename
) para renomear os diretórios.NOTA: Isso não deve ser confundido com
rename
fromutil-linux
ou com qualquer outra versão.Isso usa a
ord()
função 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 é executar a seco para mostrar orename
que faria se você permitir. Remova-o (ou substitua-o por-v
por saída detalhada) para 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 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()
comsprintf()
. por exemploOs exemplos acima funcionam se e somente se
sp.run_number
no seu script matlab no intervalo de 0 a 26 (portanto, foram produzidos caracteres de controle nos nomes dos diretórios).Para lidar com QUALQUER caractere de 1 byte (ou seja, de 0 a 255), você usaria:
Se
sp.run_number
pudesse ser> 255, você teria que usar aunpack()
função perl em vez deord()
. Eu não sei exatamente como o matlab gera um int não convertido em uma string, então você terá que experimentar. Vejoperldoc -f unpack
para detalhes.por exemplo, o seguinte descompactará os valores não assinados de 8 e 16 bits e os zerará com 5 dígitos de largura:
fonte
-n
opção, mas está me dizendo que é uma opção inválida - as informações da versão me fornecem,rename from util-linux 2.23.2
então não tenho certeza se é a mesma função #rename
utilitário.util-linux
'srename
é muito diferente, muito menos capaz, e as opções de linha de comando são incompatíveis. Se você estiver executando o debian ou similar, tente instalar ofile-rename
pacote. caso contrário, instale o pacote apropriado para sua distribuição. já pode estar instalado, tente executarprename
ou emfile-rename
vez de apenasrename
.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. Então, quandosp.run_number
foi1
, deu a você o personagem com valor1
, e depois o personagem 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 escapadas:
\001
(octal),\x01
(hex),^A
são representações comuns para o personagem com valor1
. 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.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 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-A deve fazer isso pelo menos no Bash.sl:
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/
- isso é novo para mim, mas a idéia é 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
C escapam 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\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-se ir para esse único diretório sem um caractere final ímpar ecd run_?
deve dar 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, mascd
apenas espera um.Todos eles, em certo sentido ...
No Bash, você pode usar as aspas
\000
e\x00
escapes dentro das$'...'
aspas para representar os caracteres especiais, então$'run_\033
(octal) ou$'run_\x1b'
corresponder 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á.
fonte
ls
, existem algumas opções de citação, incluindo-b
/--escape
e--quoting-style=
, ou aQUOTING_STYLE
variável de ambiente, para controlar como os caracteres não imprimíveis são mostrados. Não acho que haja uma opção para fazê-lo preferir escapes octais às versões dos personagens.O mais fácil seria criar o nome do arquivo errado e o nome do arquivo correto no mesmo ambiente em que ocorreu o acidente 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.
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!
fonte