canalizar la salida de un comando en menos o en función de la longitud de gato
Pregunta
En primer lugar, permítanme decir que este es un programación pregunta (y por lo tanto no pertenece en superusuario et. Al. ) porque estoy hablando programación de shell. Esto casi podría ser una cuestión de golf, pero no tengo una respuesta para empezar, por lo que cualquier ayuda sería muy apreciada: -)
Por lo tanto, la historia es: me gusta las cosas tubería en less
con la opción --quit-if-one-screen
porque es muy cómodo: no less
does en mi camino cuando no es necesario. O lo hace? Cuando mi pronta ya se encuentra en la parte inferior de la ventana de terminal, esta opción hace exactamente lo que quiero (es decir, se comporta como less
cat
). Sin embargo, cuando mi indicador actual es en la parte superior de la ventana, less
primera impresiones de un montón de líneas en blanco a clara la pantalla, a continuación, imprime mi archivo (corto) en la parte inferior de la pantalla, y sólo entonces se da cuenta de que hay menos de texto de una pantalla, de modo que salga y que me deben devolver pronta.
Sin embargo, este comportamiento no es muy grande, porque de todas esas líneas en blanco inútiles. Probé diferentes opciones, o escribió guiones y alias, y lo mejor que podía llegar a sería la siguiente (estoy usando zsh, por lo que la cáscara ya es capaz de duplicar las tuberías y así sucesivamente):
function catless() {
cat \
>>( bucket -$LINES | cat ) \
>>( bucket +$LINES | less )
}
Cuando bucket
es otro script que acabo de escribir, que copia entrada estándar a stdout si es menos de N líneas (con -N) o más de N (con + NORTE).
He publicado aquí: http: // snipt .NET / Gyom / copiar-stdin-a-salida estándar-o-no-dependiendo-on-longitud
Y ls | catless
casi-works. Sin embargo, por razones de sincronización, los diferentes procesos que intervienen aquí no tienen acceso a la terminal correcta y todo lo que se ejecuta en segundo plano (en particular, nunca consiguen una correcta less
aquí, y el indicador regresa muy pronto). Pero tal vez tomé el camino equivocado.
Así que, para resumir, lo que quiero es una función / script / lo que sea que pueda escribir ls | catless
y se comporta exactamente como ls | cat
cuando la salida del ls
es más corta que una pantalla, y al igual ls | less
cuando más tiempo.
¿Alguna idea?
Solución
En las noticias por menos versión 406 , veo “Don' se movió a la parte inferior de la pantalla en la primera página.”. ¿Qué versión tienes? Mi versión del sistema es 382 y se mueve a la parte inferior de la pantalla antes de imprimir (causando líneas en blanco si sólo hay una pantalla completa y -F
se utiliza).
Acabo de instalar la versión 436, y parece que hacer lo que quiera cuando se administra -FX
(ponerlo en el LESS
env var con sus otros prefs a dejar que nada utilizar esas Preferencias con sólo correr less
).
Si no puede obtener la nueva versión, puede intentar esto en su lugar:
function catless() {
local line buffer='' num=0 limit=$LINES
while IFS='' read -r line; do
buffer="$buffer$line"$'\n'
line=''
num=$(( num+1 ))
[[ $num -ge $limit ]] && break
done
if [[ $num -ge $limit ]]; then
{ printf %s "$buffer$line"; cat } | less
else
printf %s "$buffer$line"
fi
}
La clave es que la cáscara tiene que saber si la hay más líneas en el archivo de la pantalla antes de que (potencialmente) lanza less
(la técnica de multi-io que utilizó inicialmente sólo puede manejar las cosas en el fondo). Si el read
con cáscara no es lo suficientemente robusta como para usted, se puede reemplazar por volver a trabajar un poco su código:
function cat_up_to_N_lines_and_exit_success_if_more() {
# replace this with some other implmentation
# if read -r is not robust enough
local line buffer='' num=0 limit="$1"
while IFS='' read -r line; do
buffer="$buffer$line"$'\n'
line=''
num=$(( num+1 ))
[[ $num -ge $limit ]] && break
done
printf %s "$buffer$line"
[[ $num -ge $limit ]]
}
function catless() {
local limit=$LINES buffer=''
# capture first $limit lines
# the \0 business is to guard the trailing newline
buffer=${"$(
cat_up_to_N_lines_and_exit_success_if_more $limit
ec=$?
printf '\0'
exit $ec)"%$'\0'}
use_pager=$?
if [[ $use_pager -eq 0 ]]; then
{ printf '%s' "$buffer"; cat } | less
else
printf '%s' "$buffer"
fi
}
Otros consejos
La bandera -X
podría ayudarle a cabo (desde menos (1)):
-X or --no-init Disables sending the termcap initialization and deinitialization strings to the terminal. This is sometimes desirable if the deinitialization string does something unnecessary, like clearing the screen.
Por lo tanto, el siguiente debe hacer lo que quiera:
export LESS="-E -X"
O, ya que te gusta --quit-pantalla si uno, en su lugar podría:
export LESS="-F -X"
less
tiene una opción --clear-screen
(también disponible como -c
. Es posible que desee revisar su MENOS variable de entorno $ para asegurarse de que lo hace no incluir esa opción. Mía no y se comporta exactamente como usted queremos (no como usted está tratando de superar).
Puede desactivar las opciones establecidas en la variable $ MENOS en una base ad hoc mediante el uso de +
. Por ejemplo:
less -+c shortfile
También debe asegurarse de que $TERM
se ha ajustado correctamente.
Si todo lo demás falla, mira el $LESSOPEN
pre-procesador y $LESSCLOSE
características post-procesador en la sección "ENTRADA del preprocesador" de man less
para ver si eso te lleva a otro enfoque.