Estou tentando renomear todos os arquivos que começam com "m" para terem o mesmo nome, exceto com o primeiro caractere (ou "m" neste caso) removido.
Minha estratégia é:
- Liste todos os arquivos, com
ls
- Filtre pelos que eu quero, com
egrep
- Gere a string que não quero ao lado da que desejo, separada por um espaço, com
awk
, por exemplo,mfoo foo
- Alimentar
xargs
paramv mfoo foo
Algumas perguntas:
- Esta é uma boa estratégia?
- O que é melhor?
Estou preso na Etapa 3. Abaixo está como abordei o problema.
Estou trabalhando no seguinte diretório:
$ find .
.
./cat
./mbar
./mbaz
./mfoo
Consigo obter rapidamente 1-2:
$ ls | egrep '^m'
mbar
mbaz
mfoo
O passo 3 é mais difícil. Eu costumava gsub
gerar a segunda string que desejo, mas não sei como "juntá-la ao valor original separado por um espaço":
$ ls | egrep '^m' | awk '{ gsub(/^./, ""); print }'
bar
baz
foo
O passo 4 faz sentido para mim, embora não tenha certeza de como terminar o passo 3, então não posso terminá-lo ainda. Abaixo está um exemplo de como acho que deveria funcionar:
$ echo mfoo foo | xargs mv
$ find .
.
./cat
./foo
./mbar
./mbaz
Acho que estou perto, só preciso descobrir como salvar o valor antigo e imprimi-lo ao lado do valor gsubed. Eu tentei o seguinte pequeno exemplo, mas não está funcionando:
$ echo mfoo | awk '
pipe quote> { old = $0 }
pipe quote> { new = gsub(/^./, "") }
pipe quote> { print $old " " $new }'
awk: illegal field $(mfoo), name "old"
input record number 1, file
source line number 4
- Como faço uma substituição,
$0
mas salvo o valor antigo? - Por que estou recebendo esse erro?
Responder1
Isso deve lidar com toda a operação:
for file in m*; do mv "${file}" "${file#m}"; done
Antes de executar isso, verifique primeiro as coisas com
for file in m*; do echo mv "${file}" "${file#m}"; done
Isso usa o m*
glob para as etapas 1 e 2, depois ${file#m}
(que remove “m” do início de ${file}
) para a etapa 3 e, finalmente, um loop para a etapa 4.
Para responder à sua pergunta do AWK, você poderia fazer o seguinte:
echo mfoo | awk '{ print $0, substr($0, 2) }'
Variáveis AWK não usam $
, isso é apenas para campos; é daí que vem o seu erro: AWK entende $old
como “o valor do campo numerado de acordo com o valor de old
”. Também é mais fácil de ler se você colocar seus comandos em um único bloco (assumindo que eles tenham o mesmo padrão). Consertar seu script dá
echo mfoo | awk '{ old = $0; gsub(/^./, ""); print old, $0 }'
Responder2
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -l -t mv
Posix-apenasa implementação é através da -L
opção de xargs
como:
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -L 1 -t mv
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); print x, $0 }' | xargs -L 1 -t mv
Com base no queEu respondià sua consulta anterior sobre xargs
, podemos fazer bom uso desse aprendizado neste exemplo.
Modifiquei um pouco o seu awk
código: ele preserva a linha original ( $0
), já que o gsub
func vai derrotá-lo. Em seguida, juntamos o antigo e o novo para obter a linha que queremos enviar, xargs
que será invocada mv
com os argumentos corretos para efetuar a renomeação.
Responder3
Uma estratégia melhor é usar o rename
comando.
Observe que a sintaxe exata desses comandos é específica da distribuição, consulte a man
página da sua versão específica da distribuição. No Ubuntu, por exemplo, que possui uma implementação Perl do rename
, você pode usar uma regex:
rename -nono 's/^m//' m*
Nota: remova o -nono
sinalizador para realmente realizar a renomeação.