No shell, como posso tail
criar o arquivo mais recente em um diretório?
linux
shell
shell-script
Itay Moav-Malimovka
fonte
fonte
Respostas:
Você não analisar a saída de ls! Analisar a saída de ls é difícil e não confiável .
Se você deve fazer isso, recomendo usar o find. Originalmente, eu tinha aqui um exemplo simples apenas para fornecer a essência da solução, mas como essa resposta parece um pouco popular, decidi revisar isso para fornecer uma versão que seja segura para copiar / colar e usar com todas as entradas. Você está sentado confortavelmente? Começaremos com um oneliner que fornecerá o arquivo mais recente no diretório atual:
Não é exatamente um oneliner agora, é? Aqui está novamente como uma função shell e formatada para facilitar a leitura:
E agora isso como um delineador:
Se tudo mais falhar, você pode incluir a função acima
.bashrc
e considerar o problema resolvido, com uma ressalva. Se você apenas queria fazer o trabalho, não precisa ler mais.A ressalva disso é que um nome de arquivo que termina em uma ou mais novas linhas ainda não será passado
tail
corretamente. A solução do problema é complicada e considero suficiente que, se um nome de arquivo mal-intencionado for encontrado, o comportamento relativamente seguro de encontrar um erro "Nenhum arquivo desse tipo" ocorrerá em vez de algo mais perigoso.Detalhes suculentos
Para os curiosos, essa é a explicação tediosa de como funciona, por que é seguro e por que outros métodos provavelmente não são.
Danger, Will Robinson
Antes de tudo, o único byte seguro para delimitar os caminhos de arquivo é nulo, pois é o único byte proibido universalmente nos caminhos de arquivo nos sistemas Unix. É importante ao manipular qualquer lista de caminhos de arquivo usar nulo apenas como delimitador e, ao entregar um único caminho de arquivo de um programa para outro, fazê-lo de uma maneira que não engasgue com bytes arbitrários. Existem muitas maneiras aparentemente corretas de resolver esse e outros problemas que falham ao assumir (mesmo que acidentalmente) que os nomes de arquivos não terão novas linhas ou espaços. Nenhuma das suposições é segura.
Para os propósitos de hoje, a primeira etapa é obter uma lista de arquivos delimitada por nulos fora da localização. Isso é muito fácil se você tiver um
find
suporte-print0
como o GNU:Mas essa lista ainda não nos diz qual é a mais nova, por isso precisamos incluir essas informações. Eu escolho usar a
-printf
opção find, que me permite especificar quais dados aparecem na saída. Nem todas as versões defind
suporte-printf
(não é padrão), mas o GNU find sim. Se você se encontrar sem-printf
, precisará confiar em-exec stat {} \;
que ponto deve desistir de toda a esperança de portabilidade, pois issostat
também não é padrão. Por enquanto, vou seguir assumindo que você tem ferramentas GNU.Aqui, estou solicitando o formato printf,
%T@
que é o tempo de modificação em segundos desde o início da época do Unix, seguido de um período e depois de um número indicando frações de segundo. Eu adiciono a isso outro período e depois%p
(que é o caminho completo para o arquivo) antes de terminar com um byte nulo.Agora eu tenho
Pode ser óbvio, mas por uma questão de conclusão,
-maxdepth 1
impede afind
listagem do conteúdo dos subdiretórios e\! -type d
ignora os diretórios que você provavelmente não desejatail
. Até o momento, tenho arquivos no diretório atual com informações de tempo de modificação; agora, preciso classificar por esse horário de modificação.Obtê-lo na ordem certa
Por padrão,
sort
espera que sua entrada seja registros delimitados por nova linha. Se você possui o GNU,sort
pode pedir para que ele espere registros delimitados por nulo, usando a-z
opção .; por padrão,sort
não há solução. Eu só estou interessado em classificar pelos dois primeiros números (segundos e frações de segundo) e não quero classificar pelo nome do arquivo real, então eu digosort
duas coisas: primeiro, que ele deve considerar o período (.
) um delimitador de campo e segundo, que ele deve usar apenas o primeiro e o segundo campos ao considerar como classificar os registros.Antes de tudo, estou agrupando três opções curtas que não têm valor juntos;
-znr
é apenas uma maneira concisa de dizer-z -n -r
). Depois disso-t .
(o espaço é opcional) informasort
o caractere delimitador de campo e-k 1,2
especifica os números dos campos: primeiro e segundo (sort
conta os campos de um, não zero). Lembre-se de que um registro de amostra para o diretório atual se pareceria com:Isso significa que
sort
você analisará primeiro1000000000
e depois0000000000
ao solicitar este registro. A-n
opção informasort
para usar a comparação numérica ao comparar esses valores, porque os dois valores são números. Isso pode não ser importante, pois os números são de comprimento fixo, mas não causam danos.A outra opção dada
sort
é-r
para "reverso". Por padrão, a saída de uma classificação numérica será o número mais baixo primeiro,-r
altera-o para listar os números mais baixos por último e os números mais altos primeiro. Como esses números são de data e hora mais altos, será mais recente e isso colocará o registro mais recente no início da lista.Apenas os bits importantes
À medida que a lista de caminhos de arquivos surge
sort
, agora ela tem a resposta desejada que estamos procurando no topo. O que resta é encontrar uma maneira de descartar os outros registros e retirar o registro de data e hora. Infelizmente, mesmo o GNUhead
etail
não aceita switches para fazê-los operar em entradas delimitadas por nulos. Em vez disso, uso um loop while como uma espécie de homem pobrehead
.Primeiro, desmarco
IFS
para que a lista de arquivos não seja sujeita à divisão de palavras. A seguir, digoread
duas coisas: não interprete seqüências de escape na entrada (-r
) e a entrada é delimitada com um byte nulo (-d
); aqui a cadeia vazia''
é usada para indicar "sem delimitador", também conhecido como delimitado por null. Cada registro será lido na variávelrecord
para que cada vez que owhile
loop itere, ele tenha um único registro de data e hora e um único nome de arquivo. Observe que-d
é uma extensão GNU; se você tiver apenas um padrão,read
essa técnica não funcionará e você terá pouco recurso.Sabemos que a
record
variável possui três partes, todas delimitadas por caracteres de ponto. Usando ocut
utilitário, é possível extrair uma parte deles.Aqui todo o registro é passado para
printf
e de lá canalizado paracut
; no bash, você pode simplificar ainda mais isso usando uma string here paracut -d. -3f- <<<"$record"
obter melhor desempenho. Dizemoscut
duas coisas: primeiro, com-d
isso, um delimitador específico para a identificação de campos (comosort
no delimitador.
é usado). O segundocut
é instruído com-f
para imprimir apenas valores de campos específicos; a lista de campos é fornecida como um intervalo3-
que indica o valor do terceiro campo e de todos os campos seguintes. Isso significa quecut
irá ler e ignorar tudo, inclusive o segundo.
encontrado no registro, e imprimirá o restante, que é a parte do caminho do arquivo.Depois de imprimir o caminho do arquivo mais recente, não há necessidade de continuar:
break
sai do loop sem permitir que ele avance para o segundo caminho do arquivo.A única coisa que resta é a execução
tail
no caminho do arquivo retornado por este pipeline. Você deve ter notado no meu exemplo que eu fiz isso colocando o pipeline em um subshell; o que você pode não ter notado é que coloquei o subshell entre aspas duplas. Isso é importante porque, finalmente, mesmo com todo esse esforço para ser seguro para qualquer nome de arquivo, uma expansão de sub-shell não citada ainda pode quebrar as coisas. Uma explicação mais detalhada está disponível se você estiver interessado. O segundo aspecto importante, mas facilmente esquecido, da invocação detail
é que forneci a opção--
antes de expandir o nome do arquivo. Isso instruirátail
que não há mais opções sendo especificadas e tudo o que se segue é um nome de arquivo, o que torna seguro manipular os nomes de arquivos que começam com-
.fonte
tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2)
head
etail
não aceita switches para fazê-los operar em entradas delimitadas por nulos." Meu substituto parahead
:… | grep -zm <number> ""
.Se você está preocupado com nomes de arquivos com espaços,
fonte
Você pode usar:
A
$()
construção inicia um sub-shell que executa o comandols -1t
(listando todos os arquivos na ordem do tempo, um por linha) e canalizando-ohead -1
para obter a primeira linha (arquivo).A saída desse comando (o arquivo mais recente) é passada para o
tail
processamento.Lembre-se de que isso corre o risco de obter um diretório, se essa for a entrada de diretório mais recente criada. Usei esse truque em um alias para editar o arquivo de log mais recente (de um conjunto rotativo) em um diretório que continha apenas esses arquivos de log.
fonte
-1
não é necessário,ls
faz isso para você quando está em um cano. Comparels
els|cat
, por exemplo.Nos sistemas POSIX, não há como obter a entrada de diretório "última criação". Cada entrada de diretório possui
atime
,mtime
ectime
, ao contrário do Microsoft Windows,ctime
isso não significa CreationTime, mas "Hora da última alteração de status".Portanto, o melhor que você pode obter é "ajustar o último arquivo modificado recentemente", o que é explicado nas outras respostas. Eu iria para este comando:
Observe as aspas ao redor do
ls
comando. Isso faz com que o trecho funcione com quase todos os nomes de arquivos.fonte
Eu só quero ver o tamanho do arquivo mudar, você pode usar o watch.
fonte
Em
zsh
:Consulte: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers , aqui
m
denota o tempo de modificaçãom[Mwhms][-|+]n
e o anterioro
significa que ele é classificado de uma maneira (O
classifica da outra maneira). Os.
meios apenas arquivos regulares. Dentro dos colchetes,[1]
escolhe o primeiro item. Para escolher três usos[1,3]
, para obter o uso mais antigo[-1]
.É bom curto e não usa
ls
.fonte
Provavelmente existem milhões de maneiras de fazer isso, mas a maneira como eu faria é:
Os bits entre os backticks (os caracteres semelhantes a aspas) são interpretados e o resultado retornado ao final.
fonte
Um simples:
funciona muito bem para mim.
O problema é obter arquivos gerados depois que você iniciou o comando tail. Mas se você não precisar disso (como todas as soluções acima não se importam com isso), o asterisco é apenas uma solução mais simples, IMO.
fonte
fonte
Alguém postou e apagou por algum motivo, mas este é o único que funciona, então ...
fonte
ls
não é a coisa mais inteligente a fazer ...Explicação:
fonte
fonte