특정 디렉토리에 파일 이름이 있는 파일이 있습니다. 그러나 일부 파일 이름은 다음과 같습니다.
- 원래 파일 이름의 공백을 밑줄로 바꿉니다(따라서
directory/file with spaces
입력 파일에서도 공백이 됩니다).file_with_spaces
- 실제로 디렉터리의 파일과 일치하지 않을 수 있습니다.
이 두 가지 조건이 없다면 cat inputfile | awk 'commands'
파일에 원하는 명령을 적용하는 데 사용할 것입니다. 그러나 파일 이름을 찾을 수 없음 오류를 잡을 수 있는 방법이 필요합니다.
- 일치하는 파일을 찾을 때까지 밑줄을 공백으로 바꾸는 다양한 조합을 시도해 보세요.
- 밑줄을 공백으로 바꾼 후에도 일치하지 않는 파일 목록을 제공합니다.
이를 수행할 수 있는 좋은 방법이 있습니까? 한 줄 명령이 아닌 특정 유형의 스크립트가 필요한 것 같지만 솔루션을 생각할 만큼 쉘 스크립트에 익숙하지 않습니다.
답변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