
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.