我在 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
按相反顺序排序,以便最终关联数组包含给定键按字母顺序排列的第一个文件(此处是直到第二个文件的部分_
)。
您可能不想按词汇顺序进行排序,而是o
按m
修改时间进行排序(考虑到100001_XYZ_01Oct2020_0000-01Oct2020_0100
会出现这样的情况)前 100001_XYZ_30Sep2020_2200-30Sep2020_2300
例如,按词汇顺序),通过替换On
(om
将文件从最新到最旧的顺序排序),这样您最终会移动最旧的文件,而不是按词汇顺序排列第一个的文件。
或者您可以根据文件名中的第一个时间戳定义排序顺序:
zmodload zsh/datetime
bydate() strftime -rs REPLY %d%b%Y_%H%M ${${REPLY%-*}#*_*_}
并使用nO+bydate
代替On
/ om
。
使用bash
GNU 工具,您可以做一些接近的事情(不限于常规的文件,但不按修改时间排序):
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,2
with -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
有像uniq
with option -w
(GNU 版本)这样的内置工具?
mv $(ls *csv|uniq -w 10) /home/vikrant_singh_rana/uniquefiles/