
У меня есть файл с именемобщий.txtкоторый содержит список абсолютных путей. Например:
/etc
/etc/group
/var/log/syslog
У меня также есть набор файлов<имя хоста>.txtкоторые также содержат список абсолютных путей. Вот пример (назовем егоhost1.txt):
/root/.bashrc
/var/log/syslog
/etc/hosts
/bin/true
/etc
/sbin/rtmon
/etc/group
Я хотел бы удалить все пути, которые появляются вобщий.txtиз каждого файла в наборе файлов<имя файла>.txt. Итак, файл примераhost1.txtвыше будет выглядеть так:
/root/.bashrc
/etc/hosts
/bin/true
/sbin/rtmon
Для этого я написал следующий Bash-скрипт:
#!/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
У меня возникли трудности с правильной командой sed. То, что показано выше, приводит к тому, что все файлы, над которыми производились операции, становятся пустыми.
Как я могу это исправить, чтобы достичь своей цели?
решение1
#!/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
решение2
Могу ли я предложить решение, не использующее 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
Сортироватьсортирует списки в алфавитном порядке. разницанаходит различия между файлом иобщий.txt.egrepвыбирает строки, которые начинаются с >
, которые являются строками вhost1.txt.sortedно не вcommon.txt.sorted. Окончательно,седудаляет начальный символ >
(> с последующим пробелом), добавленныйразница.
Выходной список также будет в алфавитном порядке.
решение3
Сначала входные данные должны быть отсортированы в обратном порядке. Нет смысла удалять /etc, а затем искать /etc/group. Затем мы проверяем, можно ли записать файл (если нет, пропускаем). Затем ONE_PATH должен быть экранирован, и тогда sed может выполнять свою работу,
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
При наличии предоставленных тестовых данных вы получаете:
$ pr -n host1.txt
1 /root/.bashrc
2
3 /hosts
4 /bin/true
5
6 /sbin/rtmon
7
Три пустые строки.