我有一个目录,其中的文件的字符串名称均以 5 个数字开头(即 12345_a_b、23456_s_a),并且在同一目录中还有一个文本文件,其中包含以相同方式命名的文件名列表,但只有数字匹配,下划线后的任何内容都不匹配(即 12345_q_p、23456_p_l)。我想将当前目录中的文件复制到一个新目录中,但只有文件名的前 5 个数字与文本文件中每个文件名的前 5 个数字匹配的文件才行,而忽略后面的所有内容。似乎我可以使用 xargs,但我不确定如何部分匹配名称。有人可以帮忙吗?
答案1
遍历以_
作为的行IFS
,获取所需的包含数字的第一部分,然后复制以这些数字开头的文件:
shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && echo cp -it dest/ "${i}"*; done <file.txt
展开:
#!/bin/bash
shopt -s nullglob ##Expands to null string if no match while doing glob expansion,
##rather than the literal
while IFS=_ read -r i _; do ##Iterate over the lines of file.txt,
##with `_` as the `IFS` i.e. word splitting
##happens on each `_` only, variable `i`
##will contain the digits at start; `_` is a
##throwaway variable containing the rest
[[ $i =~ ^[0-9]{5}$ ]] \ ##Check if the variable contains only 5 digits
&& echo cp -it /destination/ "${i}"* ##if so, copy the relevant files starting with those digits
done <file.txt
file.txt
用实际的源文件和/destination/
实际的目标目录替换。以下echo
是用于进行试运行的命令;如果对要运行的命令满意,只需删除echo
:
shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && cp -it dest/ "${i}"*; done <file.txt
答案2
以下命令应该可以解决问题,如果愿意的话,您可以在 while 循环内将前几个变量赋值与它们的文字值进行交换。
#!/bin/bash
source_dir=/directory/containing/files
target_dir=/new/directory
list=/full/path/to/number_list
reg='^[0-9]{5}$'
while IFS= read -r line; do
line=${line:0:5}
[[ "$line" =~ $reg ]] && cp -t "$target_dir" "$source_dir"/"$line"* 2>/dev/null
done < "$list"
- 该
read
命令将逐行读取您的文件,并将每行的内容设置到变量“line”中。 - 该
cp
命令用于-t
设置要复制文件的目标,并且 glob 模式"$source_dir"/"$line"*
将在源目录中找到以行变量中的数值开头的任何文件。 - 循环
while
意味着对列表文件的每一行执行read
和命令。意味着如果列表文件中有空格,它们将包含在搜索字符串中,在这个例子中这不是直接必要的,但当您想要逐行读取文件时通常很有用。cp
IFS=
答案3
对文件运行一个循环。在循环中,使用 确定文件名是否与文本文件中的文件名匹配grep
。
&& cp
如果发现某些内容,可以使用 -q 来使用。
#!/bin/bash
while IFS= read -r file; do
grep -Eq "^${f:0:5}" your_text_file && cp ${file} /path/to/destination/
done <( (find . -type f -regex "^[0-9]{5}.*")
当你有大量文件时,这会有一些开销。但也可以用于更复杂的任务...