Écraser le fichier uniquement si les données

8

J'essaie d'écraser un fichier avec une sortie de commande, mais uniquement s'il y a une sortie. Autrement dit, je veux habituellement

mycommand > myfile

mais si cela devait écraser myfileavec des données vides, je souhaite conserver l'ancienne version de myfile. Je pensais que quelque chose en utilisant ifnedevrait être possible, à la

mycommand | ifne (cat > myfile) 

mais ça ne marche pas ...

Une approche indirecte

mycommand | tee mytempfile | ifne mv mytempfile myfile

fonctionne, mais je considère que l'utilisation de ce fichier temporaire n'est pas élégante.

Q: Pourquoi ma première idée ne fonctionne-t-elle pas? Peut-on le faire fonctionner? Ou existe-t-il une autre solution intéressante et peut-être complètement différente pour mon problème d'origine?

Hagen von Eitzen
la source
5
"Rediriger vers un fichier séparé, vérifier la taille de ce fichier et éventuellement le renommer" me semble assez simple. Pourquoi ne pas utiliser un fichier temporaire?
Jeff Schaller

Réponses:

18

Votre première approche fonctionne, il vous suffit de donner une commande à ifne(voir man ifne):

NAME
       ifne - Run command if the standard input is not empty

SYNOPSIS
       ifne [-n] command

DESCRIPTION
       ifne  runs  the  following command if and only if the standard input is
       not empty.

Vous devez donc lui donner une commande à exécuter. Vous y êtes presque, ça teemarchera:

command | ifne tee myfile > /dev/null

Si votre commande ne produit pas une énorme quantité de données, si elle est suffisamment petite pour tenir dans une variable, vous pouvez également faire:

var=$(mycommand)
[[ -n $var ]] && printf '%s\n' "$var" > myfile
terdon
la source
8

La solution piéton:

tmpfile=$(mktemp)

mycommand >"$tmpfile"
if [ -s "$tmpfile" ]; then
    cat "$tmpfile" >myfile
fi

rm -f "$tmpfile"

Autrement dit, enregistrez la sortie dans un fichier temporaire, puis testez si elle est vide ou non. S'il n'est pas vide, copiez son contenu sur votre fichier. Finalement, supprimez le fichier temporaire.

J'utilise cat "$tmpfile" >myfileplutôt que cp "$tmpfile" myfile(ou mv) pour obtenir le même effet que vous auriez obtenu mycommand >myfile, c'est-à-dire pour tronquer le fichier existant et préserver la propriété et les autorisations.

Si $TMPDIR(utilisé par mktemp) se trouve sur un système de fichiers monté en mémoire, cela n'écrira pas sur le disque autrement que lors de l'écriture myfile. Il serait en outre plus portable que l'utilisation ifne.

Kusalananda
la source