У меня есть файл с именем common.txt, который содержит список абсолютных путей. Например:

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

У меня также есть набор файлов <hostname> .txt, которые также содержат список абсолютных путей. Вот пример (назовите его host1.txt):

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

Я хотел бы удалить все пути, которые появляются в common.txt, из каждого файла в наборе файлов <filename> .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. То, что показано выше, приводит к тому, что все файлы оперируются, когда становятся пустыми.

Как я могу это исправить, чтобы достичь своей цели?

3 ответа3

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
0

Могу ли я предложить решение, которое не использует 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

сортировка сортирует списки в алфавитном порядке. diff находит различия между файлом и common.txt. egrep выбирает строки, начинающиеся с > , которые являются строками в host1.txt.sorted, но не в common.txt.sorted. Наконец, sed удаляет ведущий > (за которым следует пробел), добавленный diff.

Список вывода также будет в алфавитном порядке.

-1

Сначала вход должен быть отсортирован в обратном порядке. Бесполезно удалять /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

Есть 3 пустых строки.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .