Como posso usar curingas de estilo ms-dos com ls e mv?

9

Eu tenho a infelicidade de vir de um background MS-DOS - mas pelo menos isso me faz apreciar o quanto o Linux é mais poderoso. Eu tenho trabalhado para melhorar meu Linux-Fu, mas há algumas coisas que poderiam ser feitas com o DOS que eu não tenho certeza de como realizar mais facilmente com o Linux:

Renomeando vários arquivos - usando dois curingas

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

Eu sei que eu poderia usar find -exec aqui, mas é possível usar uma sintaxe mais curta - talvez mv com algumas flags ou sintaxe especiais? Eu acho que a chave para isso é o segundo * curinga como o Linux não deve ter um problema com o primeiro (ou seja, eu sei como selecionar os arquivos que eu quero renomear usando curingas)

Renomeando um único arquivo - usando um curinga

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

Isso seria especialmente útil ao renomear nomes de arquivos longos e de difícil controle. Eu pensei que talvez eu pudesse usar mv file1.txt $1.bak para acabar com file1.txt.bak , o que também seria aceitável, mas não tenho certeza se você pode referenciar um parâmetro $1 inline com um comando shell. Novamente neste caso em particular, é apenas conveniente como o ms-dos bastardiza o curinga * para ser usado como um tipo de correspondência de captura / substituição para parte do nome do arquivo.

Filtrando listagens de diretório com um curinga

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

Não sei qual é a sintaxe certa para fazer isso com ls , ou se é possível. Se eu fiz algo como ls t* , ele recorrerá aos diretórios que começam com t . Minha solução alternativa tem usado find . --max-depth 1 -iname "t*" ou algo parecido com ls -al | grep t - nenhuma das quais é tão curta e simples quanto dir t* é.

Finalmente, sei que posso configurar aliases para tornar esses comandos longos mais curtos, mas gostaria de aprender alguns linux-fu prontos para fazer essas coisas, porque às vezes você está conectado a um controle remoto sistema ou trabalhando em uma nova máquina.

Então, como eu posso mv e ls arquivos da mesma forma que eu usei para dir e rename arquivos?

    
por cwd 07.01.2012 / 16:34

2 respostas

15

Uma das diferenças fundamentais entre o Windows cmd e os POSIX shells é quem é responsável pelas expansões de curingas. Shells fazem todas as expansões necessárias antes de iniciar os comandos reais que você pediu. cmd principalmente passa os padrões de caracteres curinga para os comandos não modificados. (Digo principalmente, pois acho que há exceções, e as variáveis de ambiente são expandidas na maioria das circunstâncias.) Isso faz com que a escrita de rename funcione com a mesma sintaxe de cmd , o que é bastante complicado.

Mas há um rename para Linux - com argumentos completamente diferentes, confira a man page (que é um pouco concisa no meu sistema, e rename vem do pacote util-linux no meu sistema, que deve estar amplamente disponível). Sua primeira renomeação seria feita assim:

rename .txt .bak *.txt

Note que o shell faz a expansão * , então rename em si acha que foi invocado assim:

rename .txt .bak file1.txt file2.txt file3.txt ...

Então você pode adivinhar a versão de um único arquivo:

rename .txt .bak file1.txt

Se você não quiser usar rename , mas implementar isso sozinho, poderá criar uma função para isso. Supondo que você queira apenas alterar a extensão do arquivo e renomear um arquivo, veja isto:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfile é criado usando uma remoção de substring para remover a extensão original e, em seguida, concatena a nova extensão. Você pode estender essa função para lidar com vários arquivos com relativa facilidade.

Quanto à sua pergunta ls , use a opção -d . Isso impedirá que ls liste o conteúdo dos diretórios.

Demo:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Renomear curinga

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

Renomeação de arquivo único

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

O padrão ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls que não inspeciona diretórios

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv
    
por 07.01.2012 / 17:37
4

Uma coisa a ter em mente quando se trata de curingas é que eles são expandidos pelo shell. O aplicativo não sabe se você usou curingas ou digitou os nomes. Por exemplo, se você digitar rename *.txt *.bak , o comando rename verá algo como rename file1.txt file2.txt existingfile.bak . Isso não é informação suficiente para continuar.

Eu lido com a questão sobre ls primeiro, porque é mais simples. Se tudo que você quer são os nomes correspondentes, então você não precisa de ls , porque o shell já está fazendo a expansão.

echo t*

Se você quiser mais informações sobre os arquivos, passe a opção -d para ls , para dizer a ela para não listar o conteúdo dos diretórios.

ls -ld t*

Não existe um utilitário padrão para renomear arquivos, porque os primeiros sistemas unix não vêm com um. O método portátil para renomear arquivos usa um loop e é um pouco detalhado:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

Existem vários utilitários comuns para renomear arquivos, nenhum deles com garantia de ser instalado em um determinado sistema unix, mas todos eles são fáceis de instalar. Aqui estão os principais:

  • rename da suíte util-linux , disponível em todos os sistemas Linux não incorporados (e em nenhum lugar outro). No Debian e nos derivados (incluindo o Ubuntu), este comando é chamado rename.ul . Desde que não haja nenhuma ocorrência de .txt além da extensão final, você pode escrever

    rename .txt .bak *.txt
    
  • rename é um script Perl em que o Debian e seus derivados são enviados como /usr/bin/rename . Você pode renomear arquivos de acordo com os comandos arbitrários do Perl.

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmv , que pode renomear, copiar e vincular arquivos de acordo com vários padrões baseados em nomes e tem muitas opções relacionadas a o que acontece se um nome de destino já existir. Observe que você deve usar aspas para proteger os curingas da expansão pelo shell.

    mmv '*.txt' '#1.txt'
    
  • zmv é um zsh function, disponível se e somente se o seu shell for zsh. Ele pode corresponder a padrões zsh arbitrários (para que você possa corresponder nomes de arquivos de acordo com expressões regulares arbitrárias, e não apenas curingas, e pode corresponder arquivos por outros critérios, como datas e tamanhos). zmv também pode copiar e vincular.

    zmv '(*).txt' '$1.txt'
    

Se você tiver algum controle sobre as máquinas que você usa, minha recomendação é usar o zsh como seu shell (ele tem outros benefícios sobre o bash) e colocar essas linhas no seu ~/.zshrc :

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglob é um recurso zsh que informa ao shell para não expandir curingas no argumento do comando. Dessa forma, você pode escrever zmv *.txt \.txt (você sempre precisará proteger o $ em um texto de substituição).

    
por 08.01.2012 / 03:00