Hacer acciones en una list desde el caparazón

Tengo una list de packages que quiero desinstalar. El progtwig deinstalador pkg_deinstall no toma una list de packages como parámetro para desinstalar. ¿Cómo puedo desinstalar de la list (como un bucle foreach)?

 [root@fbsd01 /usr/ports/editors/vim]# pkg_info | grep proto| sed 's/\([a-z0-9]*\).*/\1/' bigreqsproto compositeproto damageproto fixesproto fontsproto inputproto kbproto randrproto renderproto xcb xcmiscproto xextproto xf86bigfontproto xinetwigproto 

Creo que un command similar a este funcionaría, pero tengo que pasar la list como parámetro y no como una secuencia: pkg_info | grep proto| sed 's/\([a-z0-9]*\).*/\1/' | head -n 1 pkg_deinstall pkg_info | grep proto| sed 's/\([a-z0-9]*\).*/\1/' | head -n 1 pkg_deinstall

Si pudiera darme algunas pistas sobre qué progtwig y qué syntax usar, sería útil. Sé que dado que es único, puede que le cueste encontrar una respuesta exacta. Si mi pregunta es demasiado complicada, tal vez alguien podría mostrarme cómo hacer acciones en un ls de files en un directory.

Para el 'foreach' más básico hay xargs , lee algunos parameters y los agrega a alguna otra línea de command. Por ejemplo, puede intentar:

 > cut -d: -f1 /etc/passwd | xargs -n1 echo user: 

Tenga en count que debe pasar un argumento -d'\n' a xargs en el caso de que los nombres de usuario puedan contener caracteres espaciales. Para agregar todos los parameters to al mismo command, use:

 > cut -d: -f1 /etc/passwd | xargs echo users: 

Para loops más generales, puede usar esto:

 > cut -d: -f1 /etc/passwd | while read i; do echo $i; done 

Esta vez, $i puede colocarse en cualquier lugar en una secuencia de uno o más commands. Las inputs se leen una línea a la vez, y se almacenan en la variable i . También es posible dividir² la línea y almacenarla en varias variables:

 > cut -d: -f1,6 /etc/passwd --output-delimiter=' ' | \ while read ij; do echo home directory of user $i is $j; done 

Tenga en count que para loops sobre nombres de file sin formatting, lo siguiente es mejor (ver comentarios):

 > for i in *.txt; do echo file: $i; done 


1. Más precisamente: todos los que permita el sistema.
2. Según la variable IFS

Hay dos forms principales de convertir una secuencia de salida en una list de arguments. La manera rápida (ya veces sucia) de hacer esto es con xargs . Por defecto, acepta una secuencia de input estándar y ejecuta un command con cada línea de la input como un argumento separado. Siempre debe tener cuidado con el formatting de la input porque los espacios y otros caracteres son fáciles de malinterpretar cuando se pasan como arguments. Los nombres de los packages, sin embargo, son relativamente seguros. No deberían include caracteres comodín de shell o líneas sueltas ni nada loco, así que aquí está lo que se vería para su command: [3]

 $ pkg_info | grep proto | sed 's/\([a-z0-9]*\).*/\1/' | xargs pkg_deinstall -n 

Un caso frecuente es que realmente necesita ejecutar el command una vez por cada línea que se procesa. En este caso, el argumento -n es útil. Puede usar -n1 para ejecutarlos uno a la vez, o incluso -n10 para ejecutarlos en lotes de diez.

 $ [pipline] | xargs -n1 pkg_deinstall -n 

Ahora supongamos que necesita agregar otro argumento después de la generación automática. En este caso, puede usar '-I' para especificar una cadena para replace con los arguments autogenerados. Esto también le permitirá hacer cosas como citar el argumento si es necesario. A continuación, puede formatear dónde se colocarán los arguments de esta manera: [1] [2]

 $ [pipline] | xargs -n1 -I{} pkg_deinstall -n "{}" --trailing-argument 

Si desea más control o ejecutar múltiples commands para cada línea de input, su próxima opción es usar un ciclo como este:

 $ [pipline] | while read line; do echo "Uninstalling $line..." pkg_deinstall -n "$line" done 

Tenga en count que pkg_deinstall utiliza automáticamente la expresión como una coincidencia parcial de coincidencia, por lo que debe tener cuidado con lo que pasa para que se desinstale. Al pasar el nombre base de algún componente del sistema, se desinstalará no solo ese componente, sino todo lo que tenga un nombre parecido o dependa de él. Esto podría ser catastrófico, por lo que siempre revise cuidadosamente su set de packages. Puede usar -n para hacer una ejecución en seco que muestre qué se haría sin realmente hacerlo [3] y / o -i para ejecutar cada paso de forma interactiva.

[1] Utilicé {} para porque find y otras funciones ejecutivas similares usan este formatting, pero cualquier cadena única funcionará.
[2] El command pkg_deinstall no tiene ningún argumento que vendría después del patern, ¡así que este es solo un ejemplo!
[3] -n a todos mis ejemplos para que, si copie y pegue el código, no haga nada, solo muestre una ejecución de testing.

No quitar las otras respuestas … Esta es solo una forma más de hacerlo:

 for pkg in $( pkg_info | grep proto| sed 's/\([a-z0-9]*\).*/\1/' ) ; do pkg_deinstall $pkg done 

Citar es una pesadilla en el ejemplo, así que personalmente tiendo a usar | while read foo ... | while read foo ... mayoría de las veces.