Estou tentando escrever uma if
declaração para testar se existem arquivos correspondentes a um determinado padrão. Se houver um arquivo de texto em um diretório, ele deverá executar um determinado script.
Meu código atualmente:
if [ -f /*.txt ]; then ./script fi
Por favor, dê algumas idéias; Eu só quero executar o script se houver um .txt
no diretório
shell-script
files
wildcards
test
user40952
fonte
fonte
/
? Além disso, falta um ponto e vírgula antesfi
.find
como explicado aqui no stackoverflow .Respostas:
retornará true somente se houver um (e apenas um) arquivo não oculto em
/
cujo nome termina.txt
e se esse arquivo for um arquivo regular ou um link simbólico para um arquivo regular.Isso ocorre porque os curingas são expandidos pelo shell antes de serem passados para o comando (aqui
[
).Portanto, se há um
/a.txt
e/b.txt
,[
serão passados 5 argumentos:[
,-f
,/a.txt
,/b.txt
e]
.[
reclamaria que-f
é dado muitos argumentos.Se você deseja verificar se o
*.txt
padrão se expande para pelo menos um arquivo não oculto (regular ou não):shopt -s nullglob
ébash
específico, mas escudos comoksh93
,zsh
,yash
,tcsh
tem declarações equivalentes.Observe que ele encontra esses arquivos lendo o conteúdo do diretório; ele não tenta acessar esses arquivos, o que o torna mais eficiente do que soluções que chamam comandos como
ls
oustat
nessa lista de arquivos computados pelo shell.O
sh
equivalente padrão seria:O problema é que, com os shells Bourne ou POSIX, se um padrão não corresponde, ele se expande. Portanto, se
*.txt
expandir*.txt
, você não sabe se é porque não há.txt
arquivo no diretório ou porque existe um arquivo chamado*.txt
. Usando[*].txt *.txt
permite discriminar entre os dois.fonte
[ -f /*.txt ]
é bastante rápido em comparação comcompgen
.[ -f /*.txt ]
estaria errado, mas no meu teste em um diretório que contém3425
arquivos,94
dos quais arquivos txt não ocultos,compgen -G "*.txt" > /dev/null 2>&1
parecem ser tão rápidos quantoset -- *.txt; [ "$#" -gt 0 ]
(20,5 segundos para ambos quando repetidos 10000 vezes no meu caso).Você sempre pode usar
find
:Explicação:
find .
: pesquisa no diretório atual-maxdepth 1
: não procurar subdiretórios-type f
: pesquise apenas arquivos regularesname "*.txt"
: procure arquivos que terminem em.txt
2>/dev/null
: redirecionar mensagens de erro para/dev/null
| grep -q .
: grep para qualquer caractere, retornará false se nenhum caractere for encontrado.&& ./script
: Executar./script
apenas se o comando anterior tiver sido bem-sucedido (&&
)fonte
find
só retorna false se tiver problemas para procurar arquivos, não se não encontrar nenhum arquivo. Você deseja canalizar a saídagrep -q .
para verificar se encontra alguma coisa.chmod a-x .
.Uma solução possível também é o Bash
compgen
. Esse comando retorna todas as correspondências possíveis para um padrão globbing e possui um código de saída indicando se algum arquivo correspondeu.Encontrei essa pergunta enquanto procurava soluções mais rápidas.
fonte
LC_ALL=C compgen -G "*.txt" > /dev/null
.Aqui está uma lista para fazê-lo:
existem arquivos
arquivos não existem
Essa abordagem utiliza os operadores
||
e&&
no bash. Estes são os operadores "ou" e "e".Portanto, se o comando stat retornar
$?
igual a 0, o primeiroecho
será chamado, se retornar 1, o segundoecho
será chamado.retornar resultados de stat
Esta questão é amplamente abordada no stackoverflow:
fonte
stat
quandols -d
pode fazer o mesmo?ls -d
lista um diretório? Não parecia funcionar quando tentei listar um diretório com arquivos,ls -d *.pl
por exemplo.&&
porls *.txt
e vai funcionar tão bem. Certifique-se de enviar o stdout e o stderr para/dev/null
o sugerido por @slm.ls *.txt
e não há arquivos presentes no diretório isso irá retornar uma$? = 2
, que continuará a funcionar com o caso, em seguida, mas esta foi uma das minhas razões para escolherstat
maisls
. Eu queria um 0 para o sucesso e um 1 para um fracasso.ls -d
é listar diretórios em vez de seu conteúdo. Ols -d
mesmo acontecelstat
com o arquivo, assim como o GNUstat
. O que os comandos de status de saída diferente de zero retornam em caso de falha é específico do sistema; faz pouco sentido fazer suposições sobre eles.Como Chazelas aponta, seu script falharia se a expansão de curinga corresponder a mais de um arquivo.
No entanto, há um truque que eu uso ( mesmo que eu não goste muito ) para contornar:
Como funciona?
A expansão de curinga corresponderá a uma matriz de nomes de arquivos; obteremos o primeiro, se houver algum; caso contrário, nulo, se não houver correspondência.
fonte
.txt
arquivos do tipo regular . Tente, por exemplo, depoismkdir a.txt; mkfifo b.txt; echo regular > c.txt
.Simples como:
wc -l
conta as linhas no curinga expandido.fonte
ls
saída e quase nunca examinar$?
diretamente, porqueif
já faz isso. Além disso, usarwc
para ver se algo aconteceu também é mal direcionado.Gosto da solução anterior do array, mas isso pode se tornar um desperdício com um grande número de arquivos - o shell usaria uma grande quantidade de memória para criar o array, e apenas o primeiro elemento seria testado.
Aqui está uma estrutura alternativa que eu testei ontem:
$ cd /etc; if [[ $(echo * | grep passwd) ]];then echo yes;else echo no;fi yes $ cd /etc; if [[ $(echo * | grep password) ]];then echo yes;else echo no;fi no
O valor de saída do grep parece estar determinando o caminho através da estrutura de controle. Isso também testa com expressões regulares em vez de padrões de shell. Alguns dos meus sistemas possuem o comando "pcregrep", que permite correspondências de regex muito mais sofisticadas.
(Eu editei esta resposta para remover um "ls" na substituição de comando depois de ler as críticas acima para analisá-las.)
fonte
se você quiser usar uma cláusula if, avalie a contagem:
fonte