根据某种模式选择并移动独特的文件

根据某种模式选择并移动独特的文件

我在 Linux 机器上有一个文件列表,这些文件在某个日期有所不同,所以我必须搜索唯一的文件,并需要将它们放在其他目录中。这里的“唯一”指的是直到第二个的文件名_,因此在下面的示例中100001_ABC也是如此。100001_XYZ

100001_ABC_25Sep2020_1200-25Sep2020_1300.csv  
100001_XYZ_30Sep2020_1300-30Sep2020_1400.csv  
100001_XYZ_30Sep2020_1400-30Sep2020_1500.csv

我希望将唯一命名的文件放置在此目录下:

/home/vikrant_singh_rana/uniquefiles/

该脚本应该只复制以下文件:

100001_ABC_25Sep2020_1200-25Sep2020_1300.csv  
100001_XYZ_30Sep2020_1300-30Sep2020_1400.csv  

这是我的 shell 脚本

#!/bin/bash
set +o posix
#reading file names into file_array
readarray -t file_array < <(
    cd "/home/vikrant_singh_rana/unzipfiles"
    printf "%s\n" * | cut -d"_" -f2 | cut -d"-" -f1 | sort -u )

#print items of array
printf '%s\n' "${file_array[@]}"


for i in "${file_array[@]}"; do
        #echo $i
        find /home/vikrant_singh_rana/unzipfiles/ -type f -name "*$i*.csv" -exec awk '!seen[$0]++' {} +
done

该脚本可以正确找到唯一的名称,但我找不到如何将它们移动到其他目录。

答案1

zsh

typeset -A files
for f (*_*_*.csv(.On)) files[${(M)f#*_*_}]=$f
mv -- $files target-directory/

glob.限定符限制为常规的文件,同时On按相反顺序排序,以便最终关联数组包含给定键按字母顺序排列的第一个文件(此处是直到第二个文件的部分_)。

您可能不想按词汇顺序进行排序,而是om修改时间进行排序(考虑到100001_XYZ_01Oct2020_0000-01Oct2020_0100会出现这样的情况) 100001_XYZ_30Sep2020_2200-30Sep2020_2300例如,按词汇顺序),通过替换Onom将文件从最新到最旧的顺序排序),这样您最终会移动最旧的文件,而不是按词汇顺序排列第一个的文件。

或者您可以根据文件名中的第一个时间戳定义排序顺序:

zmodload zsh/datetime
bydate() strftime -rs REPLY %d%b%Y_%H%M ${${REPLY%-*}#*_*_}

并使用nO+bydate代替On/ om

使用bashGNU 工具,您可以做一些接近的事情(不限于常规的文件,但不按修改时间排序):

shopt -s failglob
printf '%s\0' *_*_*.csv | sort -zsmut_ -k1,2 | xargs -r0 mv -t target-dir --

(所有-z-s-r-0-t都是 GNU 扩展)。

按从文件名中提取的时间戳进行排序可以通过以下方式完成:

printf '%s\0' *_*_*.csv |
                   #  key   year       month      day        HHMM
  LC_ALL=C sort -zt_ -k1,2 -k3.6,3.9n -k3.3,3.5M -k3.1,3.2n -k3.11,3.14n |
  LC_ALL=C sort -zsmut_ -k1,2 |
  xargs -r0 mv -t target-dir 

如果,如钥匙,您需要将第一次和第二次出现之间的部分_替换${(M)f#*_*_}${${f#*_}%%_*}(或${${(s[_])f}[2]}) 或-k1,2with -k2,2

答案2

这是任何文件名的解决方案:

target_dir="path/to/dir"

find -maxdepth 1 -type f -name '*.csv' -print0 | sort -z | awk '
    BEGIN {RS=ORS="\0"; FS=OFS="_"}
    !seen[$2]++' | xargs -r0 echo mv -t "$target_dir" --

我们通过管道使用空分隔符来保护文件名,sort按字母顺序排列文件名并GNU awk排除重复项。测试它,如果它打印出合理的移动命令,则删除echo以运行它。

(此外,上述所有空分隔都是 GNU 扩展,例如-z等)


如果你的文件名很好,这会更简单,你可以简单地执行以下操作:

ls -1 *.csv | awk -F_ '!seen[$2]++' | xargs -d'\n' echo mv -t target/dir --

请注意,glob 按字母顺序获取文件。

答案3

我只想使用一个数组来保存您见过的名称并仅移动“新”名称:

declare -A seen=()
name_seen='seen[$name]++' # work around to avoid ACE vulnerability
for i in /home/vikrant_singh_rana/unzipfiles/*_*_*; do 
    name=${i##*/} # remove directory part
    name=${name%"_${name#*_*_}"} # retain first two fields
    (( name_seen )) || mv -- "$i" /home/vikrant_singh_rana/uniquefiles/
done

答案4

为什么要使用数组、循环或者awk有像uniqwith option -w(GNU 版本)这样的内置工具?

mv $(ls *csv|uniq -w 10) /home/vikrant_singh_rana/uniquefiles/

相关内容