' ls -1 ': como listar nomes de arquivos sem extensão

ls -1 lista meus elementos assim:

foo.png bar.png foobar.png ... 

Quero listá-lo sem o .png assim:

foo bar foobar ... 

(o diretório contém apenas .png arquivos)

Alguém pode me dizer como usar grep neste caso?

Objetivo: Eu tenho um arquivo de texto onde todos os nomes estão listados sem o extensão. Quero fazer um script que compare o arquivo de texto com a pasta para ver qual arquivo está faltando.

Comentários

  • Você deseja ter cuidado com um pedido como este. O Linux não possui extensões de nome de arquivo. O Linux tem nomes de arquivos que podem ou não incluir um . neles. Embora a convenção diga para nomear seus arquivos com .png no final, não há razão para que eu não possa ‘ ter um arquivo png chamado foo.zip ou my.picture.20160518 ou apenas mypic.
  • @hymie I sei, mas meus elementos nessa pasta são todos nomeados com .png no final.
  • O que ‘ s an ” extensão “? Isso ‘ não faz parte da nomenclatura de arquivos Unix; é ‘ s transportado do VMS / NT / Windows qualquer. E vocês, jovens, saiam do meu gramado também. 🙂
  • Que ‘ s não exagere. O sistema operacional trata as extensões simplesmente como parte do nome do arquivo, mas muitos programas Unix prestam atenção a elas, desde o compilador até a GUI. O conceito certamente não é estranho ao Unix.
  • Geralmente é sugerido evitar analisar a saída de ls e canalizar a saída de ls e find, principalmente devido à possibilidade de incorrer em newline,` tabulação no nome do arquivo. Se o nome do arquivo for The new art of working on .png\NEWLINE files and other formats muitas das soluções propostas criarão problemas.

Resposta

Você só precisa do shell para este trabalho.

POSIXly:

for f in *.png; do printf "%s\n" "${f%.png}" done 

Com zsh:

print -rl -- *.png(:r) 

Comentários

  • Existem ‘ s não há necessidade de printf; echo ${f%.png} será suficiente.
  • @Conrad: o uso de echo não ‘ funcionará corretamente em alguns casos, se o nome do arquivo comece com travessão ou contenha sequências de escape.
  • @DavidConrad: Veja também unix.stackexchange.com/a/65819/38906
  • @DavidConrad Além disso, acredito que printf está integrado, assim como o echo, alguém me corrija se eu ‘ estiver errado

Resposta

ls -1 | sed -e "s/\.png$//" 

O comando sed remove (isto é, ele substitui pela string vazia) qualquer string .png encontrada no final de um nome de arquivo.

O . é escapado como \. para que seja interpretado por sed como um caractere . literal em vez de regexp . (que significa corresponder a qualquer ch aracter). A $ é a âncora de fim de linha, portanto, não corresponde a .png no meio de um nome de arquivo.

Comentários

  • Acho que o OP deseja qualquer extensão removida, mas provavelmente apenas a ” último “. Então, talvez modifique sua boa resposta com: sed 's/\.[^.]*$//'
  • sim, esse regexp iria funcionará nesse caso … mas se o OP quiser, eles devem dizer isso em vez de dizer especificamente que ” o querem listado sem o .png ”
  • O -1 não é necessário, sendo o padrão aqui.
  • @jlliagre Concordo com o cas que o -1 deve ser especificado. Ele ‘ é apenas o padrão quando o pipe está ativado, o que é uma surpresa oculta para alguns. Torná-lo explícito ajuda compreensão. Eu também faço isso em meus scripts, então sei que tipo de utput I ‘ m esperando.
  • Aviso No caso de um nome de arquivo com a chave (.png) antes de um caractere de nova linha, você apagará até aquele .png e não apenas o último. É melhor evitar canalizar e analisar a saída de ls, ele reserva muitas vezes surpresas bem escondidas … (mais algumas palavras e referências na resposta).

Resposta

Se você apenas deseja usar o bash:

for i in *; do echo "${i%.png}"; done 

Você deve alcançar grep ao tentar encontrar correspondências, não para remover / substituir que sed é mais apropriado:

find . -maxdepth 1 -name "*.png" | sed "s/\.png$//" 

Depois de decidir que precisa criar alguns subdiretórios para ordenar seus arquivos PNG, você pode facilmente alterar isso para:

find . -name "*.png" | sed "s/\.png$//" 

Comentários

  • ls -1 | sed ‘ s / .png // ‘ funciona muito bem. Obrigado!
  • A solução find canalizada para sed pode apresentar alguns problemas se você encontra um arquivo com a chave (.png) como parte do nome e logo antes de um caractere de nova linha. É melhor evitar canalizar e analisar a saída de find ou ls, ele reserva muitas vezes surpresas bem escondidas … (algumas palavras e mais referências na resposta).
  • Provavelmente substitua find por algo como echo no último exemplo. Não está claro qual a finalidade find ali e os resultados dependem da estrutura do diretório (ou seja, se você tiver um diretório files.png)
  • @BroSlow Atualizado para algo mais sensato.

Resposta

Outra resposta muito semelhante (estou surpreso a variante particular ainda não apareceu) é:

ls | sed -n "s/\.png$//p" 
  • Você não precisa do -1 opção para ls, uma vez que ls assume que se a saída padrão não for “ta terminal (é” um tubo, neste caso).
  • a opção -n para sed significa não “imprimir a linha por padrão
  • a opção /p no final da substituição significa … e imprimir esta linha se uma substituição foi feita.

A rede efeito disso é imprimir apenas as linhas que terminam em .png, com o removido. Ou seja, isso também atende à ligeira generalização da pergunta do OP, em que o diretório não contém apenas .png arquivos.

O sed -n a técnica é frequentemente útil nos casos em que você poderia usar grep + sed.

Comentários

  • Gosto de como o atendimento você costumava escrever sua resposta. Esta solução apresentará problemas com nomes de arquivos, incluindo novas linhas , ela não imprimirá a primeira parte do nome. Ainda mais se for um mais desagradável com a chave (.png) antes do caractere de nova linha: nesse caso, você imprimirá essa parte sem png, não apagando apenas a última parte. Geralmente, é sugerido evitar analisar (e canalizar) a saída de ls porque os problemas podem estar ocultos apenas onde você não está pensando …
  • @Hastur Você ‘ está correto , em princípio, e a famosa página sobre don ‘ t parse ls lista outros problemas (e soluções) ao lidar com nomes de arquivos patológicos. Mas a melhor maneira de lidar com isso é evitar nomes de arquivos patológicos (doh!); e se você puder ‘ t, ou se deve ser robusto contra eles, use find ou – possivelmente melhor – use uma linguagem mais poderosa do que sh para gerenciá-los (o fato de que sh pode fazer tudo não ‘ t significa que ‘ é a melhor escolha em cada caso). O shell é projetado para usabilidade primeiro.
  • Eu concordo, em princípio, sobre a usabilidade, mas esta variante falha quando você tem um nome do arquivo com cada nova linha dentro. Isso pode ocorrer facilmente despercebido, por exemplo, quando você copia e cola uma linha de um pdf em uma GUI, então você só pensa em ser evitado nomes de arquivos patológicos.
  • Além disso, IMHO É ‘ fácil de começar a analisar ls, mas está a caminho de problemas futuros. Freqüentemente, fazemos scripts que usaremos mais tarde, quando já esquecermos seu limite … (é ‘ é humano, é ‘ é normal). Eu propus um find exemplo (com -exec e sem tubo) mesmo se eu considerar um melhor (porque shell puro), responda o cuonglm ‘ s one , compatível com sólido e posix.
  • Isso é basicamente o que eu ‘ d faria se, por algum motivo, quisesse remover a tira .png sufixo de uma lista de nomes de arquivo.Eu não ‘ não colocaria em um script; em vez disso, ‘ d apenas digitei o comando no prompt do shell. Isso seria um lembrete de que eu ‘ m presumindo ” são ” nomes de arquivo. Há muitas coisas que eu ‘ farei em um comando manual único, quando me sentir à vontade para fazer suposições sobre o que ‘ s no diretório atual, que provavelmente não ‘ faria em um script que pudesse ser reutilizado em algum outro contexto.

Resposta

Eu “d iria para basename (assumindo a implementação GNU):

basename --suffix=.png -- *.png 

Comentários

  • Observe que se você quiser usá-lo em um pipe, pode achar útil usar o nome de base GNU ‘ s -z (ou --zero) opção para produzir separado por NUL (em vez de separado por nova linha ) saída.

Resposta

Você pode usar apenas comandos BASH para fazer isso (sem quaisquer ferramentas externas).

for file in *; do echo "${file%.*}"; done 

Isso é útil quando você está sem / usr / bin e funciona bem para nomes de arquivo l ike this.is.image.png e para todas as extensões.

Resposta

não foi o suficiente?

ls -1 | sed "s/\.png//g" 

ou em geral, isso

ls -1 | sed "s/\.[a-z]*//g" 

removerá todas as extensões

Comentários

  • Era, mas as outras soluções também funcionam.
  • Todo sistema Unix / Unix Like tem (ou deveria ter) sed instalado, pois é um utilitário obrigatório pelo padrão.
  • Certamente, mas ls faz isso de qualquer maneira sem essa opção quando sua saída não é um terminal, que é o caso aqui.
  • Aviso ls -1 | sed 's/\.[a-z]*//g' falhará se houver um nome de arquivo como Image.png.jpg.png cortando a chave o tempo todo (.png). No Unix são permitidos nomes de arquivo estranhos como The new art of working on .png?files and other formats.png onde ? é um caractere de nova linha. Infelizmente, todas as soluções que simplesmente enviam / analisam a saída ls geram problemas ms gerenciando tais casos …
  • Por que o qualificador g? Você deseja remover \.png apenas no final da linha, não sempre que aparecer.

Resposta

Não é seguro analisar ls ou canalizar find [ 1 , 2 ]

Não é seguro analisar (e enviar) a saída de ls ou find, principalmente porque é possível encontrar nos nomes de arquivo caracteres incomuns como a nova linha , a guia … Aqui, um ciclo de shell puro funcionará [ cuonglm ] .
Mesmo o comando find não canalizado com a opção -exec funcionará:

find ./*.png -exec basename {} .png \; 

Atualizações / notas : Você pode usar find . para pesquisar até mesmo os arquivos ocultos ou find ./*.png para obter apenas os não ocultos. Com find *.png -exec ... você pode ter problemas no caso de estar presente um arquivo chamado .png porque find o pegará como uma opção. Você pode adicionar -maxdepth 0 para evitar descer em diretórios nomeados como Dir_01.png ou find ./*.png -prune -exec ... quando maxdepth não é permitido (obrigado Stéphane). Se você quiser evitar listar esses diretórios, deve adicionar a opção -type f (que também excluiria outros tipos de arquivos não regulares). Dê uma olhada no man para um panorama mais completo sobre todas as opções disponíveis, e lembre-se de verificar quando são compatíveis com POSIX, para uma melhor portabilidade.

Mais algumas palavras

Pode acontecer, por exemplo, que copiando o título de um documento e colando no nome do arquivo, uma ou mais novas linhas terminem no próprio nome do arquivo.Podemos ter o azar de que um título pode conter até mesmo a chave que temos que usar antes de uma nova linha:

The new art of working on .png files and other formats. 

Se quiser testar, você pode crie nomes de arquivo como este com os comandos

touch "A file with two lines"$"\n""and This is the second.png" touch "The new art of working on .png"$"\n""files and other formats.png" 

O /bin/ls *png simples produzirá ? em vez dos caracteres não imprimíveis

A file with two lines?and This is the second.png The new art of working on .png?files and other formats.png 

Em todos os casos em que você canalize a saída de ls ou find o seguinte comando não terá nenhuma dica para entender se a linha presente vier de um novo nome de arquivo ou se seguir um caractere de nova linha no nome de arquivo precedente. Um nome desagradável , na verdade, mas ainda legal.

Um ciclo de shell com uma expansão de parâmetro de shell, ${parameter%word}, em ambos a variante com printf ou echo funcionará [ cuonglm ], [ Anthon1 ] .

for f in *.png; do printf "%s\n" "${f%.png}" ; done 

Da página de manual da expansão do parâmetro do Shell [ 3 ]

$ {parameter% word}
$ {parameter %% word}

… o resultado da expansão é o valor do parâmetro com o padrão de correspondência mais curto (o caso %) ou o padrão de correspondência mais longo (o caso %%) excluído.

Comentários

  • Além disso, os resultados de seus find command são uma variável de bit (por exemplo, se houver um diretório chamado files.png)
  • Caro @BroSlow, quando escrevi a resposta acima I tentei 13 (todas) das outras variantes presentes naquele momento, por linha de comando, em um script, lançado como argumento de uma invocação de shell. Faça o mesmo e me diga se eles se comportam da maneira que você espera. Fiz meus testes com bash 4.3.11, traço 0.5.7-4, zsh (quando necessário) 5.0.2. Sinta-se à vontade para ler esta postagem que acrescenta algo mais. Concordo com a observação de canalizar a saída de find, para isso eu sugeri expressamente -exec e escrevi no título. :-).
  • Releia o wiki novamente. Ainda acho que você precisa canalizar em seu exemplo, uma vez que ‘ é o que ‘ está sendo discutido aqui. E para a maioria das versões modernas de ls não há nenhum problema quando a saída é canalizada ou redirecionada, mas conforme mencionado no wiki pode não funcionar para todos. A maioria só irá inserir o ? no lugar dos caracteres especiais quando a saída for enviada ao terminal. ou seja, faça echo *.png | od -c e ls *.png | od -c. O problema de nova linha não é um problema com ls, é ‘ um problema com qualquer comando que não ‘ t terminação nula em ambos os lados do tubo.
  • printf "${f%.png}\n" está errado. O primeiro argumento é o formato, você não deve ‘ usar dados variáveis nele. Pode até ser visto como uma vulnerabilidade DoS (tente com um %1000000000s.png arquivo, por exemplo).
  • Você ‘ d precisa find ./*.png -prune -exec... ou ‘ d ter problemas com nomes de arquivos começando com - (e arquivos de tipo de diretório, observe que -maxdepth não é portátil)

Resposta

Use rev:

ls -1 | rev | cut -f 2- -d "." | rev 

rev inverte todos os strings (linhas); você corta tudo após o primeiro “.” e rev reverte o remanescente.

Se você quiser grep “alma”:

ls -1 | rev | cut -f 2- -d "." | rev | grep "alma" 

Comentários

  • O -1 não é necessário, sendo o padrão aqui.
  • Isso falha gravemente em um arquivo chamado My.2016.Summer.Vacation.png
  • @DavidConrad, meu erro: / Corrigi para cut -f 2-
  • Agora funciona com esse arquivo, mas ainda não com um arquivo com .png e uma nova linha logo após … Sugere-se evitar analisar ls porque adora esconder bem as surpresas … 🙂

Resposta

Se eu soubesse que o diretório só tinha arquivos com .png como extensão, teria apenas executado: ls | awk -F. "{print $1}"

Isso retornará o primeiro “campo” para qualquer coisa onde exista um nome de arquivo.extensão.

Exemplo:

[rsingh@rule51 TESTDIR]$ ls 10.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png [rsingh@rule51 TESTDIR]$ ls | awk -F. "{print $1}" 10 1 2 3 4 5 6 7 8 9 

Comentários

  • Infelizmente, falhará em todos os nomes de arquivo com mais de um ., como Image.1.png e mesmo aqueles com not nice nomes , com caracteres especiais dentro. como a nova linha ou aquele que você usará como separador de registro (entrada) em awk, RS. É sugerido evitar analisar a saída ls porque ela adora ocultar problemas que surgirão quando você não esperava. Você pode ler mais na referência 1 ou 2 . A propósito, boa ideia de usar o awk … Coloquei alguns exemplos em uma resposta.
  • Verdadeiro, no entanto, dado o exemplo fornecido por Colin, funcionaria muito bem. Para que funcione para o caso que você sugeriu, eu ‘ d provavelmente altere para: [rsingh @ rule51 TESTDIR] $ ls | sed -e ‘ s / .png $ // ‘ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny o que é .a.png.filename Não estou tentando ser difícil, mas dada a necessidade de Colin ‘, eu ‘ não tenho certeza de qual seria o problema esteja analisando ls.
  • desculpe … Acabei de perceber que não ‘ mostrei o diretório com os arquivos antes do sed modificando a saída de ‘ ls ‘ [rsingh @ rule51 TESTDIR] $ ls 10.png 2.png 4.png 6.png 8.png harry.the.bunny. png 1.png 3.png 5.png 7.png 9.png whats.a.png.filename.png [rsingh @ rule51 TESTDIR] $ ls | sed -e ‘ s / .png $ // ‘ 10 1 2 3 4 5 6 7 8 9 harry.the.bunny o que é .a.png.filename
  • note1 você precisa escapar de . em \. dentro do sed -e 's/\.png$//', mas torna-se uma resposta recém escrita. 🙁 note2 você pode tentar usar awk com algo como ls | awk -F. '{if ($NF=="png") {for (i=1;i<NF-1;i++) printf("%s.", $i) ; printf $(NF-1)"\n"}}' … mas você terá sempre o problema que o awk não consegue saber se a linha está chegando está seguindo ou não uma nova linha dentro do nome do arquivo. Tentei dizer melhor na minha resposta.
  • Obrigado Hastur, perdi isso :). Além disso, abandonei o uso de awk em favor do sed neste caso.

Resposta

de acordo com sua comentário “Eu tenho um arquivo de texto onde todos os nomes estão listados sem a extensão. Eu quero fazer um script PHP que compare o arquivo de texto com a pasta para ver qual arquivo está faltando”:

for file in $(cat yourlist) ; do [ -f "${file}.png" ] || { echo "$file : listed in yourlist, but missing in the directory" } done #assumes that filenames have no space... # otherwise use instead: # while IFS= read file ; do ...(same inner loop as above)... ; done < yourlist 

e o inverso:

for file in *.png ; do grep "^${file%.png}$" yourlist >/dev/null || { echo "$file: present in the directory but not listed in yourlist" } done #I assume there are no spaces/tabs/? before/after names in "yourlist". Change the script accordingly if there are some (or sanitize the list) 

Resposta

ls -l | sed "s/\.png$//"

É o método mais preciso, conforme destacado por @roaima. Sem os \.png arquivos de escape denominados a_png.png seriam listados como: a_.

Comentários

  • usando ls -l, conforme você faz, fornece os detalhes do arquivo, não é isso que o OP pediu sobre.

Resposta

Uma linha shell simples (ksh, bash ou zsh; não traço):

set -- *.png; printf "%s\n" "${@%.png}" 

Uma função simples (sem extensão):

ne(){ set -- *.png; printf "%s\n" "${@%.png}"; } 

Ou uma função que remove qualquer extensão fornecida (png por padrão):

ne(){ ext=${1:-png}; set -- *."$ext"; printf "%s\n" "${@%.${ext}}"; } 

Use como:

ne jpg 

Se a saída for um asterisco *, nenhum arquivo com essa extensão existe.

Resposta

Você pode tentar o seguinte feed: a saída de ls, seu superador é o “.” e como todos os seus arquivos terão name.png, você imprime a primeira coluna:
ls | awk -F"." "{print $1}"

Resposta

Se você tiver acesso ao sed, é melhor, pois irá remover a última extensão do arquivo, não importa qual seja (png, jpg, tiff, etc …)

ls | sed -e "s/\..*$//" 

Comentários

  • Quebras para nomes de arquivo como this.is.a.dotty.txt. Tente s/\.[^.]*$// em vez disso.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *