sed: удаление списка путей из набора файлов

317
Dave

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

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

0
Выводом `grep -v -f common.txt somefile.txt` является содержимое` somefile.txt` без каких-либо строк, содержащих строку в `common.txt`. xenoid 6 лет назад 1
Можете ли вы предоставить образец обоих файлов и результат, который вы хотели бы видеть? Просто чтобы я мог проверить свой ответ. Gerard H. Pille 6 лет назад 0
Я предоставил запрошенный пример для улучшения темы для будущих читателей, но у меня еще не было возможности попробовать ваше исправленное решение. Dave 6 лет назад 0
Что выводит `sed '\: ^ / etc $: d' host1.txt`? Если есть. Ответ Дэйва ниже имеет смысл. `common.txt` имеет` / etc`, поэтому строка `/ etc / hosts` будет также удалена из host1.txt,` sed` удалит ВСЕ строки, содержащие `/ etc`, в соответствии с вашим адресом. Добавьте якоря, чтобы избежать этого. Paulo 6 лет назад 0

3 ответа на вопрос

1
Dave
#!/bin/bash  set -o nounset set -o errexit set -o pipefail  declare -r SCRIPT_DIR="$( cd "$( dirname "$" )" && pwd )" declare -r FILES_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
BLiao

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

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

Вы не проверяли это, не так ли? Scott 6 лет назад 0
@ Скотт Теперь у меня есть. Gerard H. Pille 6 лет назад 0

Похожие вопросы