【发布时间】:2019-07-28 05:00:06
【问题描述】:
我目前正在使用以下命令:
grep -l -Z -E '.*?FindMyRegex' /home/user/folder/*.csv | xargs -0 -I{} mv {} /home/destination/folder
这很好用。问题是它在整个文件上使用了grep。
我只想在文件的第一行使用grep 命令。
一开始我尝试使用head -1 file |,但没有成功。
【问题讨论】:
我目前正在使用以下命令:
grep -l -Z -E '.*?FindMyRegex' /home/user/folder/*.csv | xargs -0 -I{} mv {} /home/destination/folder
这很好用。问题是它在整个文件上使用了grep。
我只想在文件的第一行使用grep 命令。
一开始我尝试使用head -1 file |,但没有成功。
【问题讨论】:
您可以尝试sed '1q' file.csv | grep ... 仅在第一行搜索正则表达式。
【讨论】:
grep -l,那么输出将是(standard input),这将不适用于mv。下面给出的 awk 答案可能更适合您的情况。
gawk 'FNR==1{if($0~/PATTERN/)
printf "mv %s %s\n",FILENAME, "/target";nextfile}' /path/*.csv
.*?FindMyRegex .*? 没有任何意义,它们可以被删除。上面的 awk (gawk) 单行代码将为您构建 mv file target 命令行。您可以检查它们,如果您对它们感到满意,请将输出传递到 |sh ,命令将被执行。
用你的正则表达式模式替换PATTERN,用真正的目标目录替换/target。
单行假设文件名不包含特殊字符(即空格),如果是这种情况,请将"s 添加到mv cmd。
【讨论】:
.*?Pattern 没有意义。不管贪不贪。
grep 在整行中查找匹配项,而不仅仅是从行首开始的匹配项。这里我们对匹配部分不感兴趣,只对是/否答案感兴趣,因此.*pattern 与pattern 相同。如果grep -E 理解非贪婪正则表达式.*?pattern,它总是匹配pattern,因为.*? 前面没有任何内容。
-E or -P 支持非贪婪之外,他的模式中的.*? 或.* 没有意义。
我要为您的脚本添加的更改是 -
for file in *.csv; do
head -1 "$file" | grep -l -Z -E '.*?FindMyRegex' | xargs -0 -I{} mv {} /home/destination/folder;
done
【讨论】:
head -1 file | ... 而不是echo $(head ...) | ... 不仅更短、更高效,而且更安全。现在,由于缺少引号,您可能会破坏第一行。另外我认为grep -l 在这里不起作用,因为输入来自管道。您可能想使用grep -q ... && mv "$file" ...。
您不需要grep 或find,只要您的文件没有嵌入换行符。
我不知道有什么简单的方法可以让sed 用空值分隔。
mv $( for f in /home/user/folder/*.csv;
do sed -ns '1 { /yourPattern/F; q; }' $f;
done ) /home/destination/folder/
编辑
用循环重写。这将运行一个单独的sed 实例来检查每个文件,但至少它不应超过第一行。如果没有命中,它将在语法上失败。
您可能需要-E,具体取决于您的正则表达式。
-n 表示不要从文件中打印记录。-s 表示将每个文件视为不同的输入 - 这样文件名并不总是第一个。
这确实需要 GNU sed 用于 F。
【讨论】:
sed 将读取每个文件中的所有行。即使它只在第一行做了一些逻辑。
2q,但它正在退出第一个文件的整个过程。 希望它有一个简单的优化器,可以识别只有一行要读取并且没有输出要生成,但我不会假设。这是awk 有点发光的情况。 :)
使用 GNU awk 查找文件名,将文件名通过管道传输到 xargs
gawk -v pattern="myRegex" '
FNR == 1 {if ($0 ~ pattern) printf "%s\0", FILENAME; nextfile}
' *.csv | xargs -0 echo mv -t destination
如果看起来没问题,删除“echo”
【讨论】:
试试这个Shellcheck-clean Bash 代码:
#! /bin/bash
shopt -s nullglob # Globs that match nothing expand to nothing
shopt -s dotglob # Globs match files whose names start with '.'
dest=/home/destination/folder
for file in *.csv ; do
head -n 1 -- "$file" | grep -qE '.*?FindMyRegex' && mv -- "$file" "$dest"
done
.csv 文件,shopt -s nullglob 可防止出错。shopt -s dotglob 确保名称以“.”开头的文件被处理。head 和mv 选项中的-- 可确保正确处理名称以- 开头的文件。"$file" 和 "$dest" 中的引号确保正确处理包含空格(实际上是 $IFS)字符(包括换行符)或全局元字符的名称。请注意,正则表达式中的.*? 可能是多余的,并且可能不会像您认为的那样做(grep -E 不会进行非贪婪匹配)。
【讨论】: