Realizando o teste -nt / -ot em um POSIX sh

11

Os utilitários test e [ internos possuem os testes -nt ("mais recente que") e -ot ("mais antigo que") na maioria dos shells, mesmo quando o shell está sendo executado em "POSIX mode "(também válido para os utilitários externos dos mesmos nomes nos sistemas aos quais tenho acesso). Esses testes são para comparar os registros de data e hora de modificação em dois arquivos. Suas semânticas documentadas variam levemente entre as implementações (com relação ao que acontece se um ou outro arquivo existir em não), mas elas não estão incluídas em a especificação POSIX. para o utilitário test .

They were not carried forward into the test utility when the conditional command was removed from the [KornShell] shell because they have not been included in the test utility built into historical implementations of the sh utility.

Supondo que gostaria de comparar o registro de data e hora de modificação entre arquivos em um script de /bin/sh e, em seguida, agir dependendo se um arquivo é mais novo que o outro, como em

if [ "$sigfile"     -nt "$timestamp" ] ||
   [ "$sigfile.tmp" -nt "$timestamp" ]
then
    return
fi

... que outro utilitário eu poderia usar, além de make (o que tornaria o restante do script difícil para dizer o mínimo)? Ou devo simplesmente presumir que ninguém nunca executará o script em uma "implementação histórica de sh " ou renuncie a escrever para um shell específico como bash ?

    
por Kusalananda 14.06.2018 / 08:57

3 respostas

10

POSIXLY:

f1=/path/to/file_1
f2=/path/to/file_2

if [ -n "$(find -L "$f1" -prune -newer "$f2")" ]; then
    printf '%s is newer than %s\n' "$f1" "$f2"
fi

O uso do caminho absoluto para arquivos impede que um falso positivo com nome de arquivo contenha apenas novas linhas.

No caso de usar caminho relativo, altere o comando find para:

find -L "$f1" -prune -newer "$f2" -exec echo . \;
    
por 14.06.2018 / 09:20
7

Este poderia ser um caso para usar um dos comandos mais antigos do Unix, ls .

x=$(ls -tdL -- "$a" "$b")
[ "$x" = "$a
$b" ]

O resultado é verdadeiro se a for mais recente que b.

    
por 14.06.2018 / 10:44
4

Você levantou uma questão interessante e fez uma reivindicação que deve ser verificada primeiro.

Eu verifiquei o comportamento de:

$shell -c '[ Makefile -nt SCCS/s.Makefile ] && echo newer'

com várias conchas. Aqui estão os resultados:

  • bash Não funciona - não imprime nada.

  • bosh funciona

  • dash Não funciona - não imprime nada.

  • ksh88 Não funciona - não imprime nada.

  • ksh93 funciona

  • mksh Não funciona - não imprime nada.

  • posh imprime: posh: [: -nt: operador / operando inesperado

  • yash funciona

  • zsh funciona em versões mais recentes , versões mais antigas não imprimem nada

Portanto, quatro dos nove shells suportam o recurso -nt e o implementam corretamente. Corretamente, neste caso, significa que é capaz de comparar os registros de data e hora em plataformas recentes que suportam granularidade de selo de data e hora menor que o segundo . Note que os arquivos que eu selecionei diferem tipicamente apenas alguns microssegundos em seus timestamps.

Como é mais fácil encontrar uma implementação find em funcionamento, recomendo substituir

if [ "$file1" -nt "$file2" ] ; then
    echo newer
fi

por uma expressão baseada em find .

if [ "$( find "$file1" -newer "$file2" )" ]; then
    echo newer
fi

funciona pelo menos enquanto $file1 não contiver apenas novas linhas.

if [ "$( find -L "$file1" -newer "$file2" -exec echo newer \; )" ]; then
    echo newer
fi

é um pouco mais lento, mas funciona corretamente.

BTW: Em relação a make não posso falar por todos fazer implementações, mas SunPro Make suporta comparação de tempo com granularidade de nanossegundos desde aprox. 20 anos, enquanto smake e gmake adicionaram esse recurso recentemente.

    
por 14.06.2018 / 10:24