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

9

Tenho a infelicidade de ter um histórico do 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 não sei ao certo como realizar com mais facilidade 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 poderia usar find -execaqui, mas é possível usar uma sintaxe mais curta - talvez mvcom alguns sinalizadores ou sintaxe especiais? Eu acho que a chave para isso é o segundo * curinga, pois o linux não deve ter um problema com o primeiro (ou seja, eu sei como selecionar os arquivos que 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 pesados. Eu pensei que talvez eu pudesse usar mv file1.txt $1.bakpara terminar com o file1.txt.bakque também seria aceitável, mas não tenho certeza se você pode referenciar um $1parâmetro inline com um comando shell. Novamente, neste caso específico, é conveniente saber como o ms-dos bastardiza o *curinga para ser usado como uma espécie de captura / substituição correspondente para parte do nome do arquivo.

Filtrando Listagens de Diretórios 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 ao certo qual é a sintaxe certa para fazer isso lsou se é mesmo possível. Se eu fiz algo como ls t*isso irá recursar em diretórios começando com t. Minha solução alternativa está usando find . --max-depth 1 -iname "t*"ou algo parecido ls -al | grep t- nenhum dos quais é tão curto e simples quanto dir t*é.

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

Então, como pode I mve lsarquivos da mesma forma que eu costumava dire renamearquivos?

cwd
fonte

Respostas:

15

Uma das diferenças fundamentais entre os cmdshells do Windows e do POSIX é quem é responsável pelas expansões de curingas. Os shells realizam todas as expansões necessárias antes de iniciar os comandos reais solicitados. passa cmd principalmente os padrões 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 escrever um renameque funcione com a mesma sintaxe que é cmdbastante complicado.

Mas existe um renamepara Linux - com argumentos completamente diferentes, confira a página de manual (que é um pouco concisa no meu sistema e renamevem do util-linuxpacote no meu sistema, que deve estar amplamente disponível). Sua primeira renomeação seria feita assim:

rename .txt .bak *.txt

Observe que o shell faz a *expansão, então renameele realmente acha que foi invocado assim:

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

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

rename .txt .bak file1.txt

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

$ 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 concatenar a nova extensão. Você pode estender essa função para lidar com vários arquivos com relativa facilidade.


Quanto à sua lspergunta, use o -dinterruptor. Isso impedirá a lslistagem do 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
Esteira
fonte
muito agradável! acho que acabei de subir um cinturão com meu linux-fu! obrigado!
Cwd
Dica para avançar um pouco com isso (e evitar armadilhas): use funções ou scripts simples para ver o que acontece quando você faz somefunc *.Extse esse padrão não corresponder a nenhum arquivo e brinque com citação para ver se você consegue passar um padrão ( sem expandi-lo) entre funções. Dica de segurança: não use em rmqualquer lugar enquanto estiver experimentando a expansão de globbing / shell :-) #
Mat
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 caracteres curinga ou digitou os nomes. Por exemplo, se você digitar rename *.txt *.bak, o renamecomando verá algo parecido rename file1.txt file2.txt existingfile.bak. Isso não é informação suficiente para continuar.

Lidarei com a questão sobre lsprimeiro, porque é mais simples. Se tudo o que você deseja são os nomes correspondentes, não precisa ls, porque o shell já está fazendo a expansão.

echo t*

Se você quiser obter mais informações sobre os arquivos, passe a -dopção para ls, para dizer 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 vieram 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 dos quais com garantia de instalação em um determinado sistema unix, mas todos fáceis de instalar. Aqui estão os principais:

  • renamedo util-linuxconjunto, disponível em todos os sistemas Linux não incorporados (e em nenhum outro lugar). No Debian e derivados (incluindo o Ubuntu), este comando é chamado rename.ul. Desde que não haja outra ocorrência .txtalém da extensão final, você pode escrever

    rename .txt .bak *.txt
    
  • renameé um script Perl que o Debian e derivados fornecem como /usr/bin/rename. Você pode renomear arquivos de acordo com comandos Perl arbitrários.

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

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

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

Se você tem algum controle sobre as máquinas que 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 diz ao shell para não expandir curingas no argumento do comando. Dessa forma, você pode escrever zmv *.txt \$1.txt(você sempre precisará proteger o $texto de substituição).

Gilles 'SO- parar de ser mau'
fonte