我有一个名为的文件通用文件包含绝对路径列表。例如:
/etc
/etc/group
/var/log/syslog
我还有一组文件<主机名>.txt还包含绝对路径列表。下面是一个例子(称之为主机1.txt):
/root/.bashrc
/var/log/syslog
/etc/hosts
/bin/true
/etc
/sbin/rtmon
/etc/group
我想删除出现在通用文件来自文件集中的每个文件<文件名>.txt. 因此,示例文件主机1.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
种类按字母顺序对列表进行排序。 差异查找文件和通用文件。egrep选出以 开头的行>
,这些行是主机1.txt.已排序但不是在普通.txt.排序。 最后,sed删除前导字符>
(即 > 后跟一个空格),添加的是差异。
输出列表也将按字母顺序排列。
答案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
有 3 行空。