スペースを「-」に置き換えて、現在のディレクトリにあるすべてのファイルのすべての文字を小文字にするスクリプトを作成しようとしています。
for x in 'ls'
do
if [ ! -f $x ]; then
continue
fi
lc = `echo $x | tr '[A-Z]' '[a-z]'`
if [ $lc != $x ]; then
mv $x $lc
fi
done
find -name "* *" -type f | rename 's/ /-/g'
次の出力が表示されます。 call: rename from to files...
ただし、名前は変更されません。たとえば、次のようになります。252680610243-Analyzed Sample2 2Jul12.txt
を使用して権限を変更しましたが、chmod 706
問題が発生しますか?私がここで何を見逃しているのでしょうか?
出力は次のとおりですbash -x lower.sh
。
+ for x in ''\''ls'\'''
+ '[' '!' -f ls ']'
+ continue
+ find -name '* *' -type f
+ rename 's/ /-/g'
call: rename from to files...
答え1
Debianとその派生製品(Ubuntuを含む)では、簡単な呼び出しで簡単に達成できます。rename
:
$ touch 'A B'
$ rename 'tr/ A-Z/-a-z/' -- *
$ ls
a-b
しかし、あなたrename
は一つです同じ名前の別のユーティリティ。
答え2
スクリプトにはいくつかの問題があります。
for x in 'ls'
1つの単語を含むリストを繰り返していますls
。おそらく、`ls`
構文解析のためにバックティックを使って書いてみたいと思いますls
。出力を解析しません。ls
:ファイル名に特殊文字(スペースなど)が含まれていると機能しません。シェルには、ディレクトリ内のファイルを一覧表示するワイルドカードと呼ばれる方法がすでに組み込まれています。だからfor x in *
。
if [ ! -f $x ]; then
ファイル名にスペースやその他の特殊文字が含まれていると機能しません。$x
外部に引用符を付けると、結果が別々の単語に分割されるためです(そして、各単語は起動時にワイルドカードパターンとして解釈されます)。この効果を避けるために$x
二重引用符を入れてくださいif [ ! -f "$x" ]; then
。あなたは覚えることができます複雑なルール、または変数の置換には常に二重引用符を使用してください。
二重引用符がないため、他のいくつかの行が壊れています。各変数置換の周りに配置します。
lc = `echo $x | tr '[A-Z]' '[a-z]'`
等号の周りにスペースがあるため、これは機能しません。行は command を実行し、lc
それを=
最初の引数(および他の引数)に渡します。シェルでは、割り当て記号=
の周りにスペースを含めることはできません。
パラメータを囲む必要はありませんtr
。ここでは、コマンドは小文字以外に[
by [
byに変更したいと言うので機能します]
。]
コマンドの置き換えには、$(…)
バックティックの代わりにドル括弧を使用することをお勧めします。`…`
バックティックには内容を引用するための複雑な規則がありますが、$(…)
バックティックには非常に直感的な構文があることを除いて、2つは同じです。全体的に、コマンドは次のようになります。lc=$(echo "$x" | tr A-Z a-z)
find -name "* *" -type f | rename 's/ /-/g'
エラーメッセージは、以下があることを示します。rename
util-linux パッケージのコマンド代わりにPerlスクリプトDebianとその派生物(Ubuntuを含む)にあります。使用する構文はPerlスクリプトにのみ適しています。
Perlスクリプトを使用すると、大文字と小文字を小文字に変更できるため、事前にこれを行う必要はありません。そして、find
サブディレクトリ(最初の部分では処理しません)のファイルの名前を変更したくない限り、それを呼び出す必要はありません。現在のディレクトリのすべてのファイル名を変更するには、次のように作成できます。
prename 'tr/A-Z /a-z-/' -- *
サブディレクトリ、シンボリックリンクなどではなく、通常のファイルの名前のみを変更するには、次のようにしますfind
。
find . -type f -maxdepth 1 -exec prename 'tr/A-Z /a-z-/' {} +
サブディレクトリのファイルにも作業を実行する場合は、ディレクトリ名にスペースまたは大文字を含めることができるため、それを保持しないように注意する必要があります。 Linuxを使用しているので、ディレクトリ名を含まない引数を使用して呼び出すことができます-execdir
。prename
find . -type f -execdir prename 'tr/A-Z /a-z-/' {} +
Perlユーティリティがないとどうなりますかrename
? util-linuxrename
ユーティリティはここで役に立ちません。ループに代替品を追加することができます。
for x in ./*; do
if [ -f "$x" ]; then
y=$(echo "$x" | tr 'A-Z-' 'a-z ')
mv "$x" "$y"
fi
done
Bashを使用すると、を呼び出す必要がなく、tr
文字列置換構造を使用できます。
for x in ./*; do
if [ -f "$x" ]; then
lc=${x,,} # convert all letters to lowercase
y=${lc// /-} # replace spaces by hyphens
if [ "$x" != "$y" ]; then
mv "$x" "$y"
fi
fi
done
サブディレクトリのファイルでも操作を実行したい場合は、再帰的なglobを使用できます(オプションで有効globstar
)。また、目次セクションに大文字やスペースが含まれる可能性があるため、これを妨げないように注意してください。
shopt -s globstar
for x in ./**/*; do
if [ -f "$x" ]; then
old_basename=${x##*/}
new_basename=${old_basename,,}
new_basename=${new_basename// /-}
if [ "$new_basename" != "$old_basename" ]; then
mv "${x%/*}/$old_basename" "${x%/*}/$new_basename"
fi
fi
done
zshでautoload -U zmv
あなたのものを入力すると.zshrc
使用できますzmv
そしてグローバル予選 .
通常のファイルのみが一致しますパラメータ拡張構造名前変更:
zmv -Q '*(.)' '${(L)f// /-}'
サブディレクトリにあるファイルに対しても操作を実行できます。
zmv -Qw '**/*(.)' '$1${(L)2// /-}'
答え3
主な問題は、ファイルを繰り返すのではなく、個々の文字列を繰り返すことです"ls"
。おそらく一重引用符の代わりにバックティックを使用しようとしました。それにもかかわらず、解析されないls
。
特に変数を引用する必要があります。知るスペースが含まれています。
Bashでは、次のことができます。
declare -l lc # whatever is stored in $lc is automatically lower cased
for x in *; do
lc=${x//[[:space:]]/} # replace all whitespace with nothing
[ "$lc" != "$x" ] && mv -- "$x" "$lc"
done
答え4
Bash 4 では、${var,,} は var を小文字に変換します。
for f in *; do f2=${f,,}; mv "$f" "${f2// /-}"; done