特定のディレクトリにファイル名を持つファイルがあります。ただし、一部のファイル名は次のとおりです。
- 元のファイル名の空白を下線で置き換えます(したがって、
directory/file with spaces
入力ファイルでも空白になります)。file_with_spaces
- 実際には、ディレクトリ内のファイルと一致しない可能性があります。
これら2つの条件がない場合は、cat inputfile | awk 'commands'
ファイルに目的のコマンドを適用するために使用します。ただし、ファイル名が見つからないエラーをキャッチする方法が必要です。
- 一致するファイルが見つかるまで、下線をスペースに置き換えるさまざまな組み合わせを試してください。
- アンダースコアを空白に置き換えた後でも、一致しないファイルのリストを提供します。
これを行うための良い方法はありますか? 1行のコマンドではなく特定の種類のスクリプトが必要なようですが、解決策を考えるのに十分なシェルスクリプトに慣れていません。
答え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