sed: eliminar una lista de rutas de un conjunto de archivos

sed: eliminar una lista de rutas de un conjunto de archivos

tengo un archivo llamadocomún.txtque contiene una lista de rutas absolutas. Por ejemplo:

/etc
/etc/group
/var/log/syslog

También tengo un conjunto de archivos.<nombre de host>.txtque también contiene una lista de rutas absolutas. Aquí hay un ejemplo (llámelohost1.txt):

/root/.bashrc
/var/log/syslog
/etc/hosts
/bin/true
/etc
/sbin/rtmon
/etc/group

Me gustaría eliminar todos los caminos que aparecen encomún.txtde cada archivo en el conjunto de archivos<nombre de archivo>.txt. Entonces, el archivo de ejemplohost1.txtarriba se convertiría en:

/root/.bashrc
/etc/hosts
/bin/true
/sbin/rtmon

He escrito el siguiente script Bash para hacer esto:

#!/bin/bash

set -o nounset
set -o errexit
set -o pipefail

while read -r ONE_PATH
do
   for ONE_FILE in host1.txt host2.txt host3.txt
   do
      sed -i '\:'"$ONE_PATH"':d' "$ONE_FILE"
   done
done < common.txt

Me resulta difícil ejecutar correctamente el comando sed. Lo que se muestra arriba da como resultado que todos los archivos operados queden vacíos.

¿Cómo puedo solucionar este problema para lograr mi objetivo?

Respuesta1

#!/bin/bash

set -o nounset
set -o errexit
set -o pipefail

declare -r SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
declare -r FILES_DIR=${SCRIPT_DIR%/*}

while read -r ONE_PATH
do
   for ONE_FILE in $(find "$FILES_DIR" -maxdepth 1 -type f -print)
   do
      if [[ "$ONE_FILE" == *".swp" ]] ||
         [[ "$ONE_FILE" == *"common.txt" ]]; then
         continue
      fi

      sed -i '\|^'"$ONE_PATH"'$|d' "$ONE_FILE"
   done

echo "Done removing $ONE_PATH"
done < "$SCRIPT_DIR"/../common.txt

exit 0

Respuesta2

¿Puedo sugerir una solución que no utilice sed?

sort common.txt > common.txt.sorted
for f in host1.txt host2.txt host3.txt ; do
    sort $f > $f.sorted
    diff common.txt.sorted $f.sorted | egrep '^>' | sed -e 's/^> //' > $f.output
    rm $f.sorted
done

clasificarordena listas en orden alfabético. diferenciaencuentra las diferencias entre el archivo a ycomún.txt.egrepselecciona líneas que comienzan con >, que son líneas enhost1.txt.ordenadopero no encomún.txt.ordenado. Finalmente,sedelimina el encabezado >(que es > seguido de un espacio) agregado pordiferencia.

La lista de salida también estará en orden alfabético.

Respuesta3

Primero, la entrada debe ordenarse al revés. No sirve de nada eliminar /etc y luego buscar /etc/group. Luego verificamos si se puede escribir en el archivo (si no, omitirlo). Entonces se debe escapar ONE_PATH y luego sed puede hacer su trabajo,

sort -r common.txt \
| while read -r ONE_PATH
do
   for ONE_FILE in host1.txt host2.txt host3.txt
   do
      if [ -w "$ONE_FILE" ]
      then
        # sed -i '\:'"$ONE_PATH"':d' "$ONE_FILE"
        ONE_PATH_ESC=$(echo "$ONE_PATH" | sed "s!/!\\\/!g")
        sed -i 's/^'"$ONE_PATH_ESC"'//' "$ONE_FILE"
      fi
   done
done

Con los datos de prueba proporcionados, obtienes:

$ pr -n host1.txt
1   /root/.bashrc
2
3   /hosts
4   /bin/true
5
6   /sbin/rtmon
7

Hay 3 líneas vacías.

información relacionada