有谁能帮我用 bash 脚本或终端命令(甚至是一个小 Java 程序)对一些文件进行排序,这些文件可以用来对文件进行排序并将文件移动到新文件夹?我已经尝试了好几天,但还没有找到办法。
我有一个名为“网页”的文件夹,里面有数百个 html 文件。粗略地说,它们分为三类,因此我需要使用不同的变量运行一个脚本三次,或者运行一个可以一次性完成所有排序和移动的脚本。
我想在文件中搜索某些字符串,然后将匹配的文件发送到新文件夹。为了简单起见,有些网页是关于政治的,有些是关于商业的,有些是关于计算机的。因此,假设我想在文件夹“网页”中的所有文件中搜索单词“选举”、“股市”和“开源”,并将包含单词“选举”的文件移动到名为“政治”的文件夹,将包含单词“股市”的文件移动到名为“商业”的文件夹,将包含术语“开源”的文件移动到名为“计算机”的文件夹。
就像我说的,我曾尝试过弄清楚,但我的努力却被人嘲笑。我不是专家。谢谢!
答案1
假设当前目录中有以下文件:
a/sm1
,内容为“a 股票市场 b”b/sm2
,内容为“x 股票市场 y”sm3
,确实如此不是包含“股市”destination
,要移动包含以下内容的文件的目录“股市”。
f
让我们查找当前目录中的所有文件(类型= 文件)( .
):
$ find . -type f
./a/sm1
./sm3
./b/sm2
但sm3
不包含“股票市场”,我们不想要它。在我们现在拥有的文件列表中,让我们搜索“股票市场”,并仅显示匹配的文件:
$ find . -type f | xargs grep --files-with-matches "stock market"
./a/sm1
./b/sm2
现在让我们获取每个文件,并将它们移动到destination
目录中:
$ for f in $(find . -type f | xargs grep --files-with-matches "stock market"); do mv $f destination/; done
确保在运行此操作之前已备份,以防它不能按照您想要的方式移动它们。
答案2
我认为一些简单的 bash 魔法可能会起到作用:
#!/bin/bash
dir1=""
dir2=""
dir3=""
shopt -s nullglob
for i in *.html)
do if [ "$(grep 'keyword1' $i)" != "" ]; then
mv -vf "$i" "$dir1"
elif [ "$(grep 'keyword2' $i)" != "" ]; then
mv -vf "$i" "$dir2"
elif [ "$(grep 'keyword3' $i)" != "" ]; then
mv -vf "$i" "$dir3"
else
echo "$i">>nomatch
fi
done
cat nomatch
答案3
这里有几种方法可以实现你的愿望:
1.find
find . -iname '*html' -type f -exec grep -q election "{}" \; -and -exec mv {} politics/ \;
解释
这里我们使用 find 的-exec
选项:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command until
an argument consisting of `;' is encountered. The string `{}'
is replaced by the current file name being processed
因此,第一个-exec
搜索文件(此处用 表示{}
)election
,第二个将执行移动。 确保仅当第一个成功且文件与模式匹配时,才会运行-and
第二个。-exec
2. find
&外壳。
这与 Cos64 的答案中的方法基本相同,但有一些改进。
find . -iname '*html' -type f -print0 |
while IFS= read -r -d '' file; do
grep -q election "$file" && mv "$file" politics/
done
解释
- 该
find
命令将查找所有名称以(或,不区分大小写)-type f
结尾的文件( ),并以 NULL 字符分隔它们。这是必要的,因为 *nix 系统中的文件名可以包含除和(NULL) 之外的任何字符。因此,您可以拥有包含空格、换行符和任何其他奇怪字符的文件。这些需要特殊处理。.html
.HTML
-iname
/
\0
while IFS= read -r -d '' file; do ... done
:这将迭代 的输出find
,将每个文件另存为$file
。 将IFS=
输入字段分隔符设置为无,这意味着我们可以正确处理文件名中的空格。 使其-d ''
读取\0
- 分隔的行,并-r
使其处理包含 的文件名\
。grep -q election "$file"
:在文件中搜索模式。-q
抑制正常输出并使其grep
静默。&& echo mv "$file" politics/
:&&
确保仅当前一个命令(grep
)成功时才会运行此命令。
3. 猛击。
该脚本与@WilhelmErasmus 的非常好的答案中的脚本非常相似,不同之处在于i)它可以从命令行获取一组模式和替换;ii)它还可以在子目录中查找文件。
#!/usr/bin/env bash
## Exit if no arguments were given
[ -z "$1" ] && echo "At least two arguments are needed." >&2 && exit 1
## Collect the arguments
args=("$@")
## Declare the $dirs associative array
declare -A dirs
## Save the arguments given in the $dirs array.
## $# is the number of arguments given, so this
## will iterate over of them, reading two by two.
for ((i=0;i<$#;i+=2));
do
## The arguments are pairs of patterns and target directories.
## Set the value of this pattern to the value of the next argument,
## its target directory.
dirs[${args[$i]}]="${args[i+1]}"
done
## Ignore globs that match no files
shopt -s nullglob
## This enables ** to match subdirectories
shopt -s globstar
## Find all .html files
for file in **/*{html,htm,HTM,HTML}
do
matched=0;
for pat in "${!dirs[@]}"
do
## Does this file match the pattern?
## The `-q` suppresses grep's output.
grep -q "$pat" "$file" &&
## Set matched to 1 if the file matches.
matched=1 &&
## If the grep succeeded, move the file
## to the corresponding directory
mv "$file" "${dirs[$pat]}" &&
## If the move succeeded, break the loop
## and move to the next pattern.
break
done
## Report files that didn't match
[[ "$matched" -eq 0 ]] && printf "No matches for '%s'\n" "$file" >&2
done
运行脚本并为其指定模式及其目标的名称。例如,使用您问题中的那些:
bash move_files.sh "election" "politics" "stock market" "business" "open source" "computers"