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
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 parased
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 defind
ouls
, ele reserva muitas vezes surpresas bem escondidas … (algumas palavras e mais referências na resposta). - Provavelmente substitua
find
por algo comoecho
no último exemplo. Não está claro qual a finalidadefind
ali e os resultados dependem da estrutura do diretório (ou seja, se você tiver um diretóriofiles.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 parals
, uma vez quels
assume que se a saída padrão não for “ta terminal (é” um tubo, neste caso). - a opção
-n
parased
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 dels
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 quesh
para gerenciá-los (o fato de quesh
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 umfind
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 comoImage.png.jpg.png
cortando a chave o tempo todo (.png
). No Unix são permitidos nomes de arquivo estranhos comoThe 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ídals
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 chamadofiles.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 defind
, 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çaecho *.png | od -c
els *.png | od -c
. O problema de nova linha não é um problema comls
, é ‘ 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 analisarls
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
.
, comoImage.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) emawk
,RS
. É sugerido evitar analisar a saídals
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 dosed -e 's/\.png$//'
, mas torna-se uma resposta recém escrita. 🙁 note2 você pode tentar usarawk
com algo comols | 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
. Tentes/\.[^.]*$//
em vez disso.
.
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 chamadofoo.zip
oumy.picture.20160518
ou apenasmypic
.ls
e canalizar a saída dels
efind
, principalmente devido à possibilidade de incorrer emnewline
,` tabulação no nome do arquivo. Se o nome do arquivo forThe new art of working on .png\NEWLINE files and other formats
muitas das soluções propostas criarão problemas.