【问题标题】:How do shell remove the first file/folder of list pattern with pairs of almost identical nameshell如何删除具有几乎相同名称对的列表模式的第一个文件/文件夹
【发布时间】:2020-10-20 14:58:02
【问题描述】:

Bash shell 如何删除第一个 ie。列表模式的早期文件/文件夹,具有几乎相同的名称对,如插图;
(真实的不是直接来自 ls 而是来自管道)

$ ls

aaa
aab
bbb
bbc
mmm
mmn
xxx
xxy

只是说明:ls | R M ...? ...终于得到了

$ ls
aaa
bbb
mmm
xxx

怎么样?

【问题讨论】:

标签: bash sed grep filesystems batch-processing


【解决方案1】:

这是 bash 的部分内容。它使用此处提供的 Levenshtein 距离实现:https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#Bash 用于计算连续 dir 条目之间的编辑距离,并通过设置适当的阈值,如果它与前一个条目足够接近,则可以修改它以删除后一个条目(因为它不会'不要删除任何东西)。

这当然会导致问题或疑问,例如,如果您有文件 aaabbbaaccaaaaccaaaaa 相比的编辑距离是相同的,但文件 bbb 的存在会改变删除行为。尝试一下,它不会按原样删除任何内容,而且它可能对您有用或提出您没有想到的要求。

#!/bin/bash
function levenshtein {
    if [ "$#" -ne "2" ]; then
        echo "Usage: $0 word1 word2" >&2
    elif [ "${#1}" -lt "${#2}" ]; then
        levenshtein "$2" "$1"
    else
        local str1len=$((${#1}))
        local str2len=$((${#2}))
        local d i j
        for i in $(seq 0 $(((str1len+1)*(str2len+1)))); do
            d[i]=0
        done
        for i in $(seq 0 $((str1len))); do
            d[$((i+0*str1len))]=$i
        done
        for j in $(seq 0 $((str2len))); do
            d[$((0+j*(str1len+1)))]=$j
        done

        for j in $(seq 1 $((str2len))); do
            for i in $(seq 1 $((str1len))); do
                [ "${1:i-1:1}" = "${2:j-1:1}" ] && local cost=0 || local cost=1
                local del=$((d[(i-1)+str1len*j]+1))
                local ins=$((d[i+str1len*(j-1)]+1))
                local alt=$((d[(i-1)+str1len*(j-1)]+cost))
                d[i+str1len*j]=$(echo -e "$del\n$ins\n$alt" | sort -n | head -1)
            done
        done
        echo ${d[str1len+str1len*(str2len)]}
    fi
}

for f in "$PWD/"*                  
do
    ret=$(levenshtein "$p" "$f")
    if [[ ret -le 1 ]]              # threshold here is 1 edit
    then
        echo rm "$f"
    else
        echo leave "$f"
    fi
    p="$f"                          # store current entry for next round
done

这是一个示例运行的输出:

$ cd /home/james/test
$ bash ../test.sh
leave /home/james/test/aaa
rm /home/james/test/aab
leave /home/james/test/bbb
rm /home/james/test/bbc

【讨论】:

    【解决方案2】:

    我的理解是:您希望从您的列表中删除以下内容:

    • 几乎相同名称的对”:从您的示例来看,当第一个字符相同时,这是正确的

    这是一个适用于 bash 的单行代码:

    ls | while read -r txt; do printf "% 40s:" "${txt:1}"; echo ${txt:0:1}; done | uniq --skip-chars 41 | sed -e 's/ *\(\S*\):\(.\)/\2\1/'
    

    编辑:我首先误解了 OP 想要删除被认为具有“几乎相同的名称”的文件/文件夹。这是我更正的单行“

    ls | tee >(uniq --check-chars 1) | sort | uniq -u  | xargs rm -v -d
    

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed):

      sed -En 'N;/^((.*).)\n\2.$/s//rm \1/p' file
      

      一次读取两行文件。

      如果第一个文件/行除了最后一个字符之外与后面的文件/行相同,请创建一个脚本将其删除。

      研究输出,如果满足要求,则:

      sed -En 'N;/^((.*).)\n\2.$/s//rm \1/p' file | sh
      

      或:

      sed -En 'N;/^((.*).)\n\2.$/s//rm \1/e' file
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-12
        • 1970-01-01
        • 2019-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-12
        相关资源
        最近更新 更多