Comment faire `head` et` tail` sur une entrée délimitée par des valeurs nulles dans bash?

18

findLa commande peut afficher les noms de fichiers sous forme de chaînes délimitées par des valeurs nulles (si elles -print0sont fournies) et les xargsconsommer avec l' -0option activée. Mais entre les deux, il est difficile de manipuler cette collection de fichiers - sortcommande a -zcommutateur, qui permet de trier ces fichiers, mais headet tailne les ont pas.

Comment puis-je faire headet tailsur ces entrées délimitées de manière pratique? (Je peux toujours créer un script rubis court et lent, mais j'espère qu'il pourrait y avoir une meilleure façon)

Rogach
la source

Réponses:

21

GNU headet taildepuis coreutils version 8.25 ont une -zoption pour cela.

Avec des versions plus anciennes ou pour des systèmes non GNU, vous pouvez essayer de permuter \0et \n:

find ... -print0 |
  tr '\0\n' '\n\0' |
  head |
  tr '\0\n' '\n\0'

Notez que certaines headimplémentations ne peuvent pas faire face à des caractères NUL (et ils ne sont pas requis par POSIX), mais où trouver des appuis -print0, headet les services publics de texte prennent en charge généralement des caractères NUL.

Vous pouvez également utiliser une fonction pour encapsuler n'importe quelle commande entre les deux trs:

nul_terminated() {
  tr '\0\n' '\n\0' | "$@" | tr '\0\n' '\n\0'
}

find ... -print0 | nul_terminated tail -n 12 | xargs -r0 ...

Gardez à l'esprit que sous nul_terminated, un \0signifie un caractère de nouvelle ligne. Ainsi, par exemple, pour remplacer \npar _:

find . -depth -name $'*\n*' -print0 | nul_terminated sed '
  p;h;s,.*/,,;s/\x0/_/g;H;g;s,[^/]*\n,,' | xargs -r0n2 mv

( \x0étant également une extension GNU).

Si vous devez exécuter plusieurs commandes de filtrage , vous pouvez effectuer:

find ... -print0 |
  nul_terminated cmd1 |
  nul_terminated cmd2 | xargs -r0 ...

Mais cela signifie exécuter quelques trcommandes redondantes . Vous pouvez également exécuter:

find ... -print0 | nul_terminated eval 'cmd1 | cmd2' | xargs -r0 ...
Stéphane Chazelas
la source
2
Cela ne va-t-il pas à l'encontre de la raison principale¹ d'utiliser \x0plutôt que de \ndélimiter les valeurs? (¹ afin que vous puissiez faire face aux valeurs qui pourraient contenir \n)
Thedward
@Thedward, non, au contraire, -print0 | tr '\n\0' '\0\n'a des lignes représentant les chemins de fichier dans lesquels les caractères de nouvelle ligne ont été convertis \0. Donc, si vous prenez la première ligne avec head -n 1et reconvertissez le \0s en retour à la ligne avec tr '\0\n' '\n\0', vous avez le premier chemin de fichier délimité NUL avec ses caractères de nouvelle ligne incorporés.
Stéphane Chazelas