list=`ls -a R*`
echo $list
Dentro de un script de shell, este comando echo mostrará una lista de todos los archivos del directorio actual que comienzan con R, pero en una línea. ¿Cómo puedo imprimir cada artículo en una línea?
Necesito un comando genérico para todos los escenarios pasando con ls
, du
, find -type -d
, etc.
Respuestas:
Si la salida del comando contiene varias líneas, entonces cite sus variables para preservar esas nuevas líneas al hacer eco:
De lo contrario, el shell se expandirá y dividirá el contenido variable en espacios en blanco (espacios, líneas nuevas, pestañas) y se perderán.
fuente
En lugar de poner mal la
ls
salida en una variable y luegoecho
ing, que elimina todos los colores, useDesde
man ls
No te aconsejo que hagas nada con la salida de
ls
, excepto mostrarlo :)Utilice, por ejemplo, globos de shell y un
for
bucle para hacer algo con los archivos ...* sin embargo, esto no incluirá el directorio actual
.
o su padre..
fuente
echo "$i"
conprintf "%s\n" "$i"
(ese no se ahogará si un nombre de archivo comienza con un "-"). En realidad, la mayoría de las veces seecho something
debe reemplazar conprintf "%s\n" "something"
.R
aquí, pero en general, sí. Sin embargo, incluso para las secuencias de comandos, intentar acomodar siempre el liderazgo-
en las rutas causa problemas: la gente asume--
, que solo algunos comandos admiten, significa el final de las opciones. He vistofind . [tests] -exec [cmd] -- {} \;
donde[cmd]
no es compatible--
. ¡Todos los caminos allí comienzan de.
todos modos! Pero ese no es un argumento en contra de reemplazarecho
conprintf '%s\n'
. Aquí, uno puede reemplazar todo el ciclo conprintf '%s\n' R/*
. Bash tieneprintf
una función incorporada, por lo que efectivamente no hay límite para el número / longitud de los argumentos.Si bien ponerlo entre comillas como sugirió @muru realmente hará lo que solicitó, también puede considerar usar una matriz para esto. Por ejemplo:
El
IFS=$'\n'
comando le dice a bash que solo divida la salida en caracteres de nueva línea para obtener cada elemento de la matriz. Sin él, se dividirá en espacios, pora file name with spaces.txt
lo que serían 5 elementos separados en lugar de uno. Sin\n
embargo, este enfoque se romperá si los nombres de archivo / directorio pueden contener líneas nuevas ( ). Guardará cada línea de la salida del comando como un elemento de la matriz.Tenga en cuenta que también he cambiado el estilo antiguo
`command`
de$(command)
los cuales es la sintaxis preferida.Ahora tiene una matriz llamada
$dirs
, cada bof cuyos elementos son una línea de la salida del comando anterior. Por ejemplo:Ahora, debido a cierta extrañeza de bash (ver aquí ), deberá restablecer
IFS
el valor original después de hacer esto. Entonces, guárdelo y vuelva a alinear:O hazlo manualmente:
Alternativamente, solo cierre la terminal actual. Su nuevo tendrá el IFS original configurado de nuevo.
fuente
du
que lo hace parecer OP está más interesado en preservar el formato de salida.Si debe almacenar la salida y desea una matriz,
mapfile
se lo pone fácil.Primero, considere si necesita almacenar la salida de su comando. Si no lo hace, simplemente ejecute el comando.
Si decide que desea leer la salida de un comando como una matriz de líneas, es cierto que una forma de hacerlo es deshabilitar el globbing, configurar la
IFS
división en líneas, usar la sustitución de comandos dentro de la(
)
sintaxis de creación de la matriz y restablecerIFS
después, que es más complejo de lo que parece. La respuesta de terdon cubre algo de ese enfoque. Pero le sugiero que utilicemapfile
, en su lugar , el comando incorporado del shell Bash para leer texto como una matriz de líneas. Aquí hay un caso simple en el que estás leyendo un archivo:Esto lee líneas en una matriz llamada
MAPFILE
. Sin la redirección de entrada , estaría leyendo desde la entrada estándar del shell (generalmente su terminal) en lugar del archivo nombrado por . Para leer en una matriz que no sea la predeterminada , pase su nombre. Por ejemplo, esto se lee en la matriz :< filename
filename
MAPFILE
lines
Otro comportamiento predeterminado que puede elegir cambiar es que los caracteres de nueva línea al final de las líneas se dejan en su lugar; aparecen como el último carácter en cada elemento de la matriz (a menos que la entrada finalice sin un carácter de nueva línea, en cuyo caso el último elemento no tiene uno). Para masticar estas nuevas líneas para que no aparezcan en la matriz, pase la
-t
opción amapfile
. Por ejemplo, esto se lee en la matrizrecords
y no escribe caracteres de nueva línea al final de sus elementos de la matriz:También puede usar
-t
sin pasar un nombre de matriz; es decir, también funciona con un nombre de matriz implícitoMAPFILE
.El
mapfile
shell integrado admite otras opciones y, alternativamente, se puede invocar comoreadarray
. Ejecutehelp mapfile
(yhelp readarray
) para más detalles.Pero no desea leer desde un archivo, desea leer desde la salida de un comando. Para lograr eso, use la sustitución del proceso . Este comando lee líneas del comando
some-command
conarguments...
sus argumentos de línea de comando y los coloca enmapfile
la matriz predeterminadaMAPFILE
, con sus caracteres de línea nueva eliminados:La sustitución del proceso reemplaza con un nombre de archivo real desde el cual se puede leer la salida de la ejecución . El archivo es una tubería con nombre en lugar de un archivo normal y, en Ubuntu, se llamará como (a veces con algún otro número que no sea ), pero no necesita preocuparse por los detalles, porque el shell se encarga de eso todo detrás de escena
<(some-command arguments...)
some-command arguments...
/dev/fd/63
63
Puede pensar que podría renunciar a la sustitución de procesos utilizando en su lugar, pero eso no funcionará porque, cuando tiene una tubería de múltiples comandos separados por , Bash ejecuta ejecuta todos los comandos en subcapas . Por lo tanto, tanto y ejecutar en sus propios entornos , pero inicializados de separar del medio ambiente de la concha en la que se ejecuta la tubería. En el subnivel donde se ejecuta, el conjunto que hace son rellenados, pero luego esa matriz se descarta cuando termina el comando. nunca se crea o modifica para la persona que llama.
some-command arguments... | mapfile -t
|
some-command arguments...
mapfile -t
mapfile -t
MAPFILE
MAPFILE
Así es como se ve el ejemplo en la respuesta de terdon , en su totalidad, si usa
mapfile
:Eso es. No necesita verificar si
IFS
se configuró , realizar un seguimiento de si no se configuró y con qué valor, configurarlo en una nueva línea, luego restablecerlo o reiniciarlo más tarde. Usted no tiene que desactivar el englobamiento (por ejemplo, conset -f
) - que es realmente necesario si va a utilizar ese método en serio, ya que los nombres de archivo pueden contener*
,?
y[
--¡entonces volver a habilitar (set +f
) después.También puede reemplazar ese ciclo en particular por completo con un solo
printf
comando, aunque esto no es realmente un beneficiomapfile
, ya que puede hacerlo si usamapfile
u otro método para completar la matriz. Aquí hay una versión más corta:Es importante tener en cuenta que, como menciona Terdon , operar línea por línea no siempre es apropiado y no funcionará correctamente con nombres de archivo que contengan nuevas líneas. Recomiendo no nombrar archivos de esa manera, pero puede suceder, incluso por accidente.
No existe realmente una solución única para todos.
Usted solicitó "un comando genérico para todos los escenarios", y el enfoque de utilizar
mapfile
algo se acerca a ese objetivo, pero le insto a que reconsidere sus requisitos.La tarea que se muestra arriba se logra mejor con solo un
find
comando:También puede usar un comando externo como
sed
agregarDIR:
al comienzo de cada línea. Esto podría decirse que es algo feo, y a diferencia de ese comando find, agregará "prefijos" adicionales dentro de los nombres de archivo que contienen líneas nuevas, pero funciona independientemente de su entrada, por lo que cumple con sus requisitos y aún es preferible leer la salida en un variable o matriz :Si necesita enumerar y también realizar una acción en cada directorio encontrado, como ejecutar
some-command
y pasar la ruta del directorio como argumento, tambiénfind
puede hacerlo:Como otro ejemplo, volvamos a la tarea general de agregar un prefijo a cada línea. Supongamos que quiero ver la salida de
help mapfile
pero numerar las líneas. Realmente no lo usaríamapfile
para esto, ni ningún otro método que lo lea en una variable de shell o matriz de shell. Suponiendohelp mapfile | cat -n
que no da el formato que quiero, puedo usarawk
:Leer toda la salida de un comando en una sola variable o matriz a veces es útil y apropiado, pero tiene grandes desventajas. No solo tiene que lidiar con la complejidad adicional de usar su shell cuando un comando existente o una combinación de comandos existentes ya pueden hacer lo que necesita también o mejor, sino que toda la salida del comando debe almacenarse en la memoria. A veces puede saber que no es un problema, pero a veces puede estar procesando un archivo grande.
Una alternativa que se intenta comúnmente, y a veces se hace bien, es leer la entrada línea por línea con
read -r
un bucle. Si no necesita almacenar líneas anteriores mientras opera en líneas posteriores, y tiene que usar una entrada larga, entonces puede ser mejor quemapfile
. Pero, también, debe evitarse en los casos en que simplemente puede canalizarlo a un comando que puede hacer el trabajo, que es la mayoría de los casos .fuente