我有某个目录中文件的文件名文件。但是,某些文件名可能:
- 将原始文件名中的空格替换为下划线(因此在输入文件中
directory/file with spaces
变为如此)file_with_spaces
- 实际上可能与目录中的文件不匹配
如果我没有这两个条件,我会用来cat inputfile | awk 'commands'
处理在文件上应用我想要的命令。但是,我想要某种方法来捕获文件名未找到错误,并且:
- 尝试用空格替换下划线的不同组合,直到找到匹配的文件
- 提供没有匹配项的文件列表,即使在用空格替换下划线之后也是如此。
有没有好的方法可以做到这一点?我怀疑需要某种类型的脚本(而不是单行命令),但我对 shell 脚本还不够熟悉,无法想到解决方案。
答案1
我使用的方法是获取 ls 的输出,设置一个将转换后的名称映射回原始名称的数组,然后处理输入文件的每一行。如果输入在数组中,则输出数组的值,否则将输入行添加到文件中missing
。所以就像把它放在一个文件中,更改为并作为参数directory
运行它inputfile
#!/usr/bin/awk
# set up an array t of translations
BEGIN {
while (("ls" | getline )>0) {
k=$0
gsub(/ /,"_")
if ($0 in t) {
print "$0 matches more than one file" > /dev/stderr
exit(2)
}
t[$0]=k
}
close("ls")
}
{ if ($0 in t) {
print t[$0]
} else {
print $0 > "../missing"
}
}
答案2
将修改后的文件名转换为与原始文件匹配的模式。
#!/bin/bash
shopt -s nullglob extglob
IFS=$'\n'
while read -r filename; do
pattern=${filename//\\/\\\\}
pattern=${pattern//\[/\\\[}
pattern=${pattern//\(/\\\(}
pattern=${pattern//\*/\\\*}
pattern=${pattern//\?/\\\?}
pattern=${pattern//_/'[ _]'}
matches=($pattern@())
case ${#matches[@]} in
0) echo "No match for $filename";;
1) echo "$filename found as ${matches[0]}";;
*) echo "$filename matches ${#matches[@]} files";;
esac
done <inputfile
答案3
通过zsh
,您可以使用它的近似匹配功能:
approx-cat() {
emulate -L zsh
setopt extendedglob nullglob
local err files
for ((err = 0; err <= $1; err++)); do
files=((#a$err)$2)
case $#files in
(1) cat -- $files; return;;
(0) ;;
(*) echo >&2 "$#files found at error count $err:"
printf >&2 ' "%s"\n' $files
return 1;;
esac
done
return 1
}
并调用为:
approx-cat 3 'directory/file with spaces'
最多允许 3错误在文件名中。
例子:
$ approx-cat 3 /ebc/passwds
2 found at error count 2:
"/etc/passwd"
"/etc/passwd-"
$ approx-cat 3 /ebc/Issue
Debian GNU/Linux stretch/sid \n \l