Bash 从列表中删除重复的文件名,忽略目录
我正在运行Linux并编写BASH脚本 我有一个文本文件,每行都有一个绝对的文件路径。我发现有时我的一个文本文件会有一个相同的文件,但列在不同的路径下。我想删除这些包含相同文件的行,以便该文件只显示一次 例如,如果我有:Bash 从列表中删除重复的文件名,忽略目录,bash,shell,unix,Bash,Shell,Unix,我正在运行Linux并编写BASH脚本 我有一个文本文件,每行都有一个绝对的文件路径。我发现有时我的一个文本文件会有一个相同的文件,但列在不同的路径下。我想删除这些包含相同文件的行,以便该文件只显示一次 例如,如果我有: /path/to/number1/file1.txt /path/to/number1/file2.txt /path/to/number1/file3.txt /path/to/number2/file3.txt 我希望生成的文件包含: /path/to/number1/f
/path/to/number1/file1.txt
/path/to/number1/file2.txt
/path/to/number1/file3.txt
/path/to/number2/file3.txt
我希望生成的文件包含:
/path/to/number1/file1.txt
/path/to/number1/file2.txt
/path/to/number1/file3.txt
路径长度是可变的(例如,无法保证文件名位于字段4)
我曾经尝试过使用uniq解决类似问题的方法,但是uniq似乎没有提供匹配最后一个字段的选项,也不允许设置分隔符。有哪些解决方案?使用awk,您可以:
awk -F\/ '{ path=""; if ( path1[$NF] == "" ) { print $0;path1[$NF]=$0 } }' filename
我们在awk中构建一个可变路径。文件名由$NF(最后一个字段以/)表示。我们构建一个文件名数组(path1)及其关联路径。对于文件中的每个记录/行,将引用此数组以检查文件名是否有路径条目。如果存在条目,则忽略记录,从而停止任何复制,否则将使用awk打印路径,您可以执行以下操作:
awk -F\/ '{ path=""; if ( path1[$NF] == "" ) { print $0;path1[$NF]=$0 } }' filename
我们在awk中构建一个可变路径。文件名由$NF(最后一个字段以/)表示。我们构建一个文件名数组(path1)及其关联路径。对于文件中的每个记录/行,将引用此数组以检查文件名是否有路径条目。如果存在条目,则忽略记录,从而停止任何复制,否则将打印路径Shortawk解决方案:
awk -F'/' '!a[$NF]++' file
-将-F'/'
视为字段分隔符/
-确保只输出唯一的文件名(包含在最后一列![$NF]+
)$NF
/path/to/number1/file1.txt
/path/to/number1/file2.txt
/path/to/number1/file3.txt
短awk解决方案:
awk -F'/' '!a[$NF]++' file
-将-F'/'
视为字段分隔符/
-确保只输出唯一的文件名(包含在最后一列![$NF]+
)$NF
/path/to/number1/file1.txt
/path/to/number1/file2.txt
/path/to/number1/file3.txt
有一个使用纯bash内置的表达性解决方案 使用关联数组作为集合,可以通过连续检查键是否已被使用来完成,在这种情况下,只需继续循环即可
# We will have a set which will contain existing filenames as keys.
declare -A fileSet
while read fullPath; do
fileName="${fullPath##*/}" # basename
if [ ! -n "${fileSet[$fileName]}" ]; then # If the file is not already in the set.
echo $fullPath >> $FILEOUTPUT
fileSet[$fileName]=1
fi
done < $FILEINPUT
#我们将有一个包含现有文件名作为密钥的集合。
声明-文件集
阅读全文时;做
fileName=“${fullPath##*/}”#basename
如果[!-n“${fileSet[$fileName]}”];然后#如果文件不在集合中。
echo$fullPath>>$FILEOUTPUT
文件集[$fileName]=1
fi
完成<$FILEINPUT
有一个使用纯bash内置的表达性解决方案
使用关联数组作为集合,可以通过连续检查键是否已被使用来完成,在这种情况下,只需继续循环即可
# We will have a set which will contain existing filenames as keys.
declare -A fileSet
while read fullPath; do
fileName="${fullPath##*/}" # basename
if [ ! -n "${fileSet[$fileName]}" ]; then # If the file is not already in the set.
echo $fullPath >> $FILEOUTPUT
fileSet[$fileName]=1
fi
done < $FILEINPUT
#我们将有一个包含现有文件名作为密钥的集合。
声明-文件集
阅读全文时;做
fileName=“${fullPath##*/}”#basename
如果[!-n“${fileSet[$fileName]}”];然后#如果文件不在集合中。
echo$fullPath>>$FILEOUTPUT
文件集[$fileName]=1
fi
完成<$FILEINPUT
您不需要所有这些工作来构建路径
,因为您只使用路径$NF
,它与$0
完全相同。注:for(in)可以而且几乎总是以与输入不同的顺序生成文件名;目前还不清楚这是否与本作品有关。@dave_thompson_085文件的顺序实际上对我来说并不重要。@dave_thompson_085,你提出了一个有效的观点,我修改了代码以简化并考虑排序。你不需要所有的工作来构建path
,因为你只使用path$NF
,这与$0
完全相同。注:for(in)可以而且几乎总是以与输入不同的顺序生成文件名;不清楚这是否与此操作有关。@dave_thompson_085文件的顺序在我的情况下实际上并不重要。@dave_thompson_085,你提出了一个有效的观点,我修改了代码以简化并考虑顺序。你的示例输出与描述不匹配。@Williampersell也许我所说的令人困惑。我有成千上万的“文件列表”,其中包含一些文件的绝对路径。发现其中一些列表包含相同的文件,但路径不同(两个相同的文件)。我只想从列表中删除其中一个相同的文件,删除哪一个文件无关紧要,因为它们是相同的。您的示例输出与描述不匹配。@williampersell也许我说的有些混乱。我有成千上万的“文件列表”,其中包含一些文件的绝对路径。发现其中一些列表包含相同的文件,但路径不同(两个相同的文件)。我只想从列表中删除其中一个相同的文件,删除哪一个并不重要,因为它们是相同的。