查找两个目录之间的共同文件 - 排除文件扩展名
find common files between two directories - exclude file extension
我有两个目录,其中的文件以两个不同的扩展名结尾:
文件夹A调用的配置文件(1204个文件)
file.fasta.profile
file1.fasta.profile
file2.fasta.profile
名为 dssp 的文件夹 B(1348 个文件)
file.dssp
file1.dssp
file2.dssp
file3.dssp #<-- odd one out
我在 folder B
中有一些文件在 folder A
中找不到,应该删除,例如 file3.profile
将被删除,因为它在 folder A
中找不到.我只想保留文件名中常见的那些,但不包括扩展名以在两个 中以 1204 个文件结尾
我看到一些 bash 行使用 diff 但它没有考虑这种情况,我要删除的是那些在相应的其他文件中找不到的行。
这里有一个方法:
- 对于A和B目录,列出每个目录下的文件,不带扩展名。
- 比较两个列表,只显示两个列表中都没有出现的文件。
代码:
#!/bin/bash
>a.list
>b.list
for file in A/*
do
basename "${file%.*}" >>a.list
done
for file in B/*
do
basename "${file%.*}" >>b.list
done
comm -23 <(sort a.list) <(sort b.list) >delete.list
while IFS= read -r line; do
rm -v A/"$line"\.*
done < "delete.list"
# cleanup
rm -f a.list b.list delete.list
"${file%.*}"
删除扩展
basename
删除路径
comm -23 ...
只显示只出现在a.list 中的行
编辑 5 月 10 日:我的初始代码列出了文件,但没有删除它。现在可以了。
试试这个 Shellcheck-clean Bash 程序:
#! /bin/bash -p
folder_a=PATH_TO_FOLDER_A
folder_b=PATH_TO_FOLDER_B
shopt -s nullglob
for ppath in "$folder_a"/*.profile; do
pfile=${ppath##*/}
dfile=${pfile%.profile}.dssp
dpath=$folder_b/$dfile
[[ -f $dpath ]] || echo rm -v -- "$ppath"
done
- 它目前只打印它会做什么。一旦确定
echo
会按照您的要求进行操作,请将其删除。
shopt -s nullglob
使 glob 在没有匹配项时扩展为空(否则它们扩展为 glob 模式本身,这在程序中几乎没有用)。
- 有关使用的字符串操作机制的信息,请参阅 Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?))(例如
${ppath##*/}
)。
与find
:
find 'folder A' -type f -name '*.fasta.profile' -exec sh -c \
'! [ -f "folder B/$(basename -s .fasta.profile "").dssp" ]' _ {} \; -print
将 -print
替换为 -delete
,当您确信它可以满足您的要求时。
或者,也许快一点:
find 'folder A' -type f -name '*.fasta.profile' -exec sh -c \
'for f in "$@"; do [ -f "folder B/$(basename -s .fasta.profile "$f").dssp" ] || echo rm "$f"; done' _ {} +
当您确信它可以满足您的要求时,请删除 echo
。
Python版本:
编辑:现在支持多个扩展
#!/usr/bin/python3
import glob, os
def removeext(filename):
index = filename.find(".")
return(filename[:index])
setA = set(map(removeext,os.listdir('A')))
print("Files in directory A: " + str(setA))
setB = set(map(removeext,os.listdir('B')))
print("Files in directory B: " + str(setB))
setDiff = setA.difference(setB)
print("Files only in directory A: " + str(setDiff))
for filename in setDiff:
file_path = "A/" + filename + ".*"
for file in glob.glob(file_path):
print("file=" + file)
os.remove(file)
与我上面的 bash 版本几乎相同。
- 列出 A 中的文件
- 列出 B 中的文件
- 获取差异列表
- 删除与 A 的差异
测试输出,在 Linux Mint 上完成,bash 4.4.20
mint:~/SO$ l
drwxr-xr-x 2 Nic3500 Nic3500 4096 May 10 10:36 A/
drwxr-xr-x 2 Nic3500 Nic3500 4096 May 10 10:36 B/
mint:~/SO$ l A
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file1.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:14 file3.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:36 file4.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file.fasta.profile
mint:~/SO$ l B
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:05 file1.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file3.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:05 file.dssp
mint:~/SO$ ./so.py
Files in directory A: {'file1', 'file', 'file3', 'file2', 'file4'}
Files in directory B: {'file1', 'file', 'file3', 'file2'}
Files only in directory A: {'file4'}
file=A/file4.fasta.profile
mint:~/SO$ l A
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file1.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:14 file3.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file.fasta.profile
我有两个目录,其中的文件以两个不同的扩展名结尾:
文件夹A调用的配置文件(1204个文件)
file.fasta.profile
file1.fasta.profile
file2.fasta.profile
名为 dssp 的文件夹 B(1348 个文件)
file.dssp
file1.dssp
file2.dssp
file3.dssp #<-- odd one out
我在 folder B
中有一些文件在 folder A
中找不到,应该删除,例如 file3.profile
将被删除,因为它在 folder A
中找不到.我只想保留文件名中常见的那些,但不包括扩展名以在两个 中以 1204 个文件结尾
我看到一些 bash 行使用 diff 但它没有考虑这种情况,我要删除的是那些在相应的其他文件中找不到的行。
这里有一个方法:
- 对于A和B目录,列出每个目录下的文件,不带扩展名。
- 比较两个列表,只显示两个列表中都没有出现的文件。
代码:
#!/bin/bash
>a.list
>b.list
for file in A/*
do
basename "${file%.*}" >>a.list
done
for file in B/*
do
basename "${file%.*}" >>b.list
done
comm -23 <(sort a.list) <(sort b.list) >delete.list
while IFS= read -r line; do
rm -v A/"$line"\.*
done < "delete.list"
# cleanup
rm -f a.list b.list delete.list
"${file%.*}"
删除扩展basename
删除路径comm -23 ...
只显示只出现在a.list 中的行
编辑 5 月 10 日:我的初始代码列出了文件,但没有删除它。现在可以了。
试试这个 Shellcheck-clean Bash 程序:
#! /bin/bash -p
folder_a=PATH_TO_FOLDER_A
folder_b=PATH_TO_FOLDER_B
shopt -s nullglob
for ppath in "$folder_a"/*.profile; do
pfile=${ppath##*/}
dfile=${pfile%.profile}.dssp
dpath=$folder_b/$dfile
[[ -f $dpath ]] || echo rm -v -- "$ppath"
done
- 它目前只打印它会做什么。一旦确定
echo
会按照您的要求进行操作,请将其删除。 shopt -s nullglob
使 glob 在没有匹配项时扩展为空(否则它们扩展为 glob 模式本身,这在程序中几乎没有用)。- 有关使用的字符串操作机制的信息,请参阅 Removing part of a string (BashFAQ/100 (How do I do string manipulation in bash?))(例如
${ppath##*/}
)。
与find
:
find 'folder A' -type f -name '*.fasta.profile' -exec sh -c \
'! [ -f "folder B/$(basename -s .fasta.profile "").dssp" ]' _ {} \; -print
将 -print
替换为 -delete
,当您确信它可以满足您的要求时。
或者,也许快一点:
find 'folder A' -type f -name '*.fasta.profile' -exec sh -c \
'for f in "$@"; do [ -f "folder B/$(basename -s .fasta.profile "$f").dssp" ] || echo rm "$f"; done' _ {} +
当您确信它可以满足您的要求时,请删除 echo
。
Python版本:
编辑:现在支持多个扩展
#!/usr/bin/python3
import glob, os
def removeext(filename):
index = filename.find(".")
return(filename[:index])
setA = set(map(removeext,os.listdir('A')))
print("Files in directory A: " + str(setA))
setB = set(map(removeext,os.listdir('B')))
print("Files in directory B: " + str(setB))
setDiff = setA.difference(setB)
print("Files only in directory A: " + str(setDiff))
for filename in setDiff:
file_path = "A/" + filename + ".*"
for file in glob.glob(file_path):
print("file=" + file)
os.remove(file)
与我上面的 bash 版本几乎相同。
- 列出 A 中的文件
- 列出 B 中的文件
- 获取差异列表
- 删除与 A 的差异
测试输出,在 Linux Mint 上完成,bash 4.4.20
mint:~/SO$ l
drwxr-xr-x 2 Nic3500 Nic3500 4096 May 10 10:36 A/
drwxr-xr-x 2 Nic3500 Nic3500 4096 May 10 10:36 B/
mint:~/SO$ l A
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file1.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:14 file3.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:36 file4.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file.fasta.profile
mint:~/SO$ l B
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:05 file1.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file3.dssp
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:05 file.dssp
mint:~/SO$ ./so.py
Files in directory A: {'file1', 'file', 'file3', 'file2', 'file4'}
Files in directory B: {'file1', 'file', 'file3', 'file2'}
Files only in directory A: {'file4'}
file=A/file4.fasta.profile
mint:~/SO$ l A
total 0
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file1.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file2.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:14 file3.fasta.profile
-rw-r--r-- 1 Nic3500 Nic3500 0 May 10 10:06 file.fasta.profile