Escriba iterativamente en el mismo archivo de sustitución de procesos en MacOs

Escriba iterativamente en el mismo archivo de sustitución de procesos en MacOs

El siguiente código bash-fu funciona bien en Linux pero falla en MacOS:

files="foo bar"

echo PROG 1
for file in $files
do
  echo $file | tee -a tempfile.txt
done

sort -u tempfile.txt

echo PROG 2
function trick {
  for file in $files
  do
    echo $file | tee -a $1
  done
}

trick >(sort -u)

El error es:

PROG 1
foo
bar
bar
foo
PROG 2
tee: /dev/fd/63: Bad file descriptor
foo
tee: /dev/fd/63: Bad file descriptor
bar

En Linux PROG 2escribe las mismas líneas que PROG 1sin errores. En MacOS parece que el identificador de tubería está cerrado o no se hereda.

Lo anterior es la muestra minimizada para reproducir el problema. En realidad, proceso mucho tanto la salida vinculada como el identificador redirigido. Algo en el espíritu de

function trick {
  for file in $files
  do
     echo $file | tee -a $1 | grep -Eo "^.."
  done
}

trick >(sort -u | sed 's|o|x|g')

El código no funciona en Bash 4.1, pero funciona en Bash 4.4 en múltiples distribuciones (Arch, Ubuntu y Debian)

Respuesta1

macOS viene con una versión muy antigua de bash. Ese error (que el descriptor de archivo para la sustitución de ese proceso se cierra antes de llamar teeen ese contexto)¹ se solucionó en versiones más recientes. Obtendría el mismo problema en Linux (con un mensaje de error diferente, ya que /dev/fd/xallí se implementa de manera diferente) con bash 3.2 allí.

Aquí podrías usar zsho ksh93en su lugar. Es una buena idea evitar basheste lugar de todos modos ya queno espera procesos en sustituciones de procesos(zsh los espera, se le puede indicar a ksh93 que waitlo haga).

Tenga en cuenta que incluso con la última versión (4.4.12 al momento de escribir este artículo), bashtodavía hay algunos errores aquí como:

$ bash -c 'eval cat <(echo test)'
test # OK but:
$ bash -c 'eval "echo foo;cat" <(echo test)'
foo
cat: /dev/fd/63: No such file or directory
$ bash -c 'eval f=<(echo test) "; cat \$f"'
cat: /dev/fd/63: No such file or directory

y algunos todavía activados por tuberías como:

$ cat file
echo "$1"
cat "$1"
$ bash -c 'source ./file <(echo test)'
/dev/fd/63
test  # OK but:
$ cat file2
echo "$1" | wc -c
cat "$1"
$ bash -c 'source ./file2 <(echo test)'
11
cat: /dev/fd/63: No such file or directory

¹ bash cierra ese descriptor de archivo tan pronto como hay una canalización. Un reproductor más corto:

$ bash -c 'f() { :; cat "$1"; }; f <(echo OK)'
OK
$ bash -c 'f() { :|:; cat "$1"; }; f <(echo test)'
cat: /dev/fd/63: No such file or directory

información relacionada