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)
ls -1
lista meus elementos da seguinte forma:
foo.png
bar.png
foobar.png
...
Eu quero que ele seja listado 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 são listados sem a extensão. Eu quero fazer um script que compara o arquivo de texto com a pasta para ver qual arquivo está faltando.
ls -1 | sed -e 's/\.png$//'
O comando sed
remove (isto é, substitui pela string vazia) qualquer string .png
encontrada no end de um nome de arquivo.
O .
é salvo como \.
, de modo que é interpretado por sed
como um caractere literal .
, em vez do coexe% regexp% (que corresponde a qualquer caractere). O .
é a âncora de fim de linha, portanto, não corresponde a $
no meio de um nome de arquivo.
Se você quiser apenas usar o bash:
for i in *; do echo "${i%.png}"; done
Você deve alcançar grep
ao tentar encontrar correspondências, e não remover / substituir por sed
mais apropriado:
find . -maxdepth 1 -name "*.png" | sed 's/\.png$//'
Depois que você decidir criar alguns subdiretórios para organizar seus arquivos PNG, altere-os facilmente para:
find . -name "*.png" | sed 's/\.png$//'
Eu escolheria basename
(assumindo a implementação do GNU):
basename --suffix=.png -- *
Outra resposta muito semelhante (estou surpreso que essa variante ainda não tenha aparecido) é:
ls | sed -n 's/\.png$//p'
-1
para ls
, pois ls
assume que, se a saída padrão não for um terminal (é um canal, nesse caso). -n
para sed
significa "não imprimir a linha por padrão" /p
no final da substituição significa "... e imprima esta linha se uma substituição tiver sido feita". O efeito líquido disso é imprimir apenas as linhas que terminam em .png
, com o .png
removido. Ou seja, isso também atende à pequena generalização da pergunta do OP, em que o diretório não contém apenas .png
de arquivos.
A técnica sed -n
costuma ser útil em casos em que você poderia usar o grep + sed.
Você pode usar apenas comandos BASH para fazer isso (sem ferramentas externas).
for file in *; do echo "${file%.*}"; done
Isso é útil quando você está sem / usr / bin e funciona bem para nomes de arquivos como this.is.image.png e para todas as extensões.
ls
ou canalizar find
[ 1 , 2 ]
Não é seguro analisar (e canalizar) a saída de ls
ou find
, principalmente porque é possível encontrar nos nomes de arquivo caracteres não usuais como newline , a aba ... 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 pelos arquivos ocultos ou find ./*.png
para obter apenas os não ocultos. Com find *.png -exec ...
você pode ter problema no caso de estar presente um arquivo chamado .png
porque o find irá obtê-lo como 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, deverá 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 eles são compatíveis com POSIX, para uma melhor portabilidade.
Pode acontecer, por exemplo, copiar o título de um documento e colá-lo no nome do arquivo, uma ou mais novas linhas terminarão no próprio nome do arquivo. Podemos ser ainda mais infelizes que um título possa conter até mesmo a chave que temos de usar antes de uma nova linha:
The new art of working on .png
files and other formats.
Se você quiser testar, você pode criar 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 simples /bin/ls *png
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ê enviará a saída de ls
ou find
, o seguinte comando não terá nenhuma dica para entender se a linha atual vem de um novo arquivo name ou se segue um caracter newline no precedente nome do arquivo . Um nome desagradável de fato, mas ainda legal.
Um ciclo de shell com um shell Expansão de Parâmetros, ${parameter%word}
, na variante com printf
ou echo
funcionará [ cuonglm ], [ Anthon1 ] .
for f in *.png; do printf "%s\n" "${f%.png}" ; done
A partir da página man da Expansão do Parâmetro do Shell [ 3 ]
${parameter%word}
${parameter%%word}... the result of the expansion is the value of parameter with the shortest matching pattern (the ‘%’ case) or the longest matching pattern (the ‘%%’ case) deleted.
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
Use rev
:
ls -1 | rev | cut -f 2- -d "." | rev
rev
inverte todas as strings (linhas); você corta tudo depois do primeiro '. e reverte novamente o remanescente.
Se você quiser grep
'alma':
ls -1 | rev | cut -f 2- -d "." | rev | grep 'alma'
de acordo com o seu comentário "Eu tenho um arquivo de texto onde todos os nomes são listados sem a extensão. Eu quero fazer um script PHP que compara 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)
ls -l | sed 's/\.png$//'
É o método mais preciso, conforme destacado pelo @roaima. Sem os arquivos \.png
com escape chamados a_png.png
seriam listados como: a_
.
Se eu soubesse que o diretório tinha apenas arquivos com extensão .png, eu teria acabado de executar: ls | awk -F. '{print $1}'
Isso retornará o primeiro "campo" para qualquer coisa onde houver 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
Uma linha de shell simples (ksh, bash ou zsh; not dash):
set -- *.png; printf '%s\n' "${@%.png}"
Uma função simples (de No Extension):
ne(){ set -- *.png; printf '%s\n' "${@%.png}"; }
Ou uma função que remova qualquer extensão dada (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 *
, não existe nenhum arquivo com essa extensão.
Você pode tentar o seguinte feed awk a saída de seu supervisor é o "." e como todos os seus arquivos terão nome.png você imprime a primeira coluna: ls | awk -F"." '{print $1}'
Se você tem acesso ao sed, isso é melhor, pois tira a última extensão do arquivo, não importa o que seja (png, jpg, tiff, etc ...)
ls | sed -e 's/\..*$//'