Como faço uma substituição para `$0` mas salvo o valor antigo?

Como faço uma substituição para `$0` mas salvo o valor antigo?

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 é:

  1. Liste todos os arquivos, comls
  2. Filtre pelos que eu quero, comegrep
  3. Gere a string que não quero ao lado da que desejo, separada por um espaço, com awk, por exemplo,mfoo foo
  4. Alimentar xargsparamv 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 gsubgerar 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, $0mas 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 $oldcomo “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 -Lopção de xargscomo:

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 awkcódigo: ele preserva a linha original ( $0), já que o gsubfunc vai derrotá-lo. Em seguida, juntamos o antigo e o novo para obter a linha que queremos enviar, xargsque será invocada mvcom os argumentos corretos para efetuar a renomeação.

Responder3

Uma estratégia melhor é usar o renamecomando.

Observe que a sintaxe exata desses comandos é específica da distribuição, consulte a manpá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 -nonosinalizador para realmente realizar a renomeação.

informação relacionada