
次のスクリプトを実行すると、次のエラーが発生します。
cp: cannot stat ls
スクリプトの内容
#!/bin/bash
#make copies of all files in directory
cd /home/don
LIST='ls'
for i in $LIST; do
ORIG=$i
DEST=$i.old
cp $ORIG $DEST
echo "Copied $i"
done
誰か問題が分かりますか?
答え1
主なエラーの1つは、コマンドを使用しようとしているls
が、変数LISTには文字列「ls」しか含まれていないことです。構文でコマンド置換を使用できます$(command)
。この場合、簡単に使用できる形式で情報が得られないため、お勧めしません。ほとんどの場合、出力を解析する間違いls
。
このような状況では、シェルパターンマッチング(別名:グロビング。
代わりに、スクリプトで次の方法をお勧めします。
#!/bin/bash
#make copies of all files in directory
for i in /home/don/* ; do
if [[ -f $i ]]; then
orig="$i"
dest="${i}.old"
cp "$orig" "$dest"
echo "Copied $i"
else
echo "${i} is not a file"
fi
done
- これは、ディレクトリ内のすべてのファイルを一致させるためにシェルのグロビングを使用します。は、
./*
現在のディレクトリ (.
) 内のすべてのものを意味します。 - この
if
ステートメントは、一致するものがファイルであるかどうかをチェックし (ディレクトリとリンクでは失敗します)、一致する場合はコピー シーケンスを実行します。 - システム環境変数は大文字なので、変数名を小文字に変更しました。これにより、不要な名前の衝突を回避できます。
答え2
そうですね、スクリプトに小さなエラーがあります。4行目で実行しようとしていたのはlsしたがって、一重引用符ではなく、シンボルで囲む必要があります。「スクリプトは次のように変更されます
LIST=`ls`
上記のようにスクリプトを更新してみてください。
$(ls)
ただし、まったく使用しないことをお勧めします。ループ ヘッダーでシェル グロブを使用することをお勧めします。
for i in *; do
などデイビッド・アンダーソン氏以下に、変数値に引用符を使用できるとコメントしました(「$i」) を使用してください。そうしないと、ファイル名のスペースで問題が発生する可能性があります。find とプロセス置換を組み合わせて使用することで、この問題を回避できます。
while read l; do
i=$(basename "$l")
done < <(find . -name '*' -maxdepth 1)
詳細な回答と説明は以下に記載されています。アロニカル氏今後のスクリプト作成の改善のために参考にしてください。
答え3
「検索」コマンドのバージョン
スクリプトは、解析したり glob をいじったりするfind
必要なく、ワンライナー コマンドとして実行できます。ls
質問を読む限り、あなたの目標は現在のディレクトリにあるすべてのファイルのコピーを作成することです。そのためには、適切なコマンドは次のようになります。
find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
これは、(現在の)ディレクトリfind
内のすべてのファイルに対して を操作し、ファイルごとに を呼び出します(したがって)。は再帰的であるため、検索の深さを制限する必要があり、そのためフラグ が必要です。フラグ は、検索結果の 1 つとしてリストされることを回避するためのものです。.
cp
\;
find
-maxdepth
-mindepth
.
サンプル実行:
$ touch "file one" "file two"
$ find . -maxdepth 1 -mindepth 1 -exec cp {} {}".old" \;
$ ls -1
file one
file one.old
file two
file two.old
$
注記:cp
ディレクトリに関してまだエラーが出ます。これに対処する方法はいくつかあります。
-type f
1)フラグを使用してファイルのみをフィルタリングすることもできますfind
。
find . -mindepth 1 -maxdepth 1 -type f -exec cp {} {}".old" \;
2)cp -r
ディレクトリのコピーにも使用する
find . -mindepth 1 -maxdepth 1 -exec cp -r {} {}".old" \;
Pythonワンライナー
これは、前のものより少し長いですfind
が、それでも目的は達成され、特殊なファイル名の問題もありません。
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") for f in os.listdir(".") if os.path.isfile("./" + f)]'
サンプル実行:
$ touch "test file 1" "testfile 2"
$ python -c 'import shutil;import os;[shutil.copyfile(f,f + ".old")
> for f in os.listdir(".")
> if os.path.isfile("./" + f)]'
$ ls -1
test file 1
test file 1.old
testfile 2
testfile 2.old
$
ディレクトリを含めるには、shutil.copytree(source,destination)
python -c 'import shutil; import os;[shutil.copyfile(f,f + ".old") if os.path.isfile("./" + f) else shutil.copytree(f,f + ".old") for f in os.listdir(".")]'
directory_one.old/
すでに存在する場合は失敗することに注意してください