私は次の課題を実行しており、私のプログラムに関する質問があります。
以下の説明に従ってファイルをコピーするシェルスクリプトを作成します。サフィックスはコマンドライン引数として送信する必要があります。指定されたサフィックスが適切な現在のディレクトリ内の各ファイルについて、ユーザーにそのファイルを保存する必要があるかどうかを尋ねるメッセージが表示されます。答えが「はい」の場合は、ファイルをバックアップディレクトリにコピーする必要があります。ディレクトリが存在しない場合は、新規作成する必要があります。
これが私がしたことです:
#!/bin/sh
usage() {
echo "Usage : prog.sh <POSTFIX> " >&2
exit 1
}
if [ $# -ne 1 ]; then
usage
fi
list=$(ls)
for name in $list; do
case $name in
*.$@)
printf "Do you want to save the file ?\n"
read answer
case $answer in
Yes|yes|y)
ls backup 2>/dev/null || mkdir backup
mv $name backup
;;
No|no|n);;
esac ;;
esac
done
次のフォルダがあるとしましょう。 (バックアップディレクトリに移動します。)
bar.txt foobar.txt foo.txt mbar.txt
これは私の結果です。
Do you want to save the file ?
y
Do you want to save the file ?
y
bar.txt // Why is it printing the file during the output ?
Do you want to save the file ?
y
bar.txt foobar.txt // ??
Do you want to save the file ?
y
bar.txt foobar.txt foo.txt // ??
ls backup 2>/dev/null || mkdir backup
(代わりに)このように書くことができることを知っています
if [ ! -d backup ] ; then
mkdir backup
fi
しかし、私のプログラムが出力中にバックアップに移動したファイルを印刷する理由を知りたいです。
答え1
ls backup 2>/dev/null
ディレクトリに移動した各ファイルに対して操作を実行したため、そのファイルはbackup
次にls
表示されます。
ただし、スクリプト全体を次の単一のコマンドに置き換えることができますrsync
。
rsync --include='*.{txt,csv,xyz}' /path/to/source/* /path/to/backup/
バラよりman rsync
同期後に削除する方法の詳細をご覧ください。
答え2
次の行が原因です。
ls backup 2>/dev/null
stdoutではなくstderrのみをリダイレクトします。以下を行う必要があります。
ls backup >/dev/null 2>&1 || mkdir backup
それ以外の場合:
mkdir -p backup
また、シェルチェックに表示される警告にも注意を払う必要があります。
$ shellcheck ./p.sh
In ./p.sh line 18:
read answer
^--^ SC2162: read without -r will mangle backslashes.
In ./p.sh line 24:
mv $name backup
^---^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
mv "$name" backup
For more information:
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
https://www.shellcheck.net/wiki/SC2162 -- read without -r will mangle backs...
答え3
Bashが許可されている場合は、次のようにします。
#!/usr/bin/env bash
if (( $# == 0 )); then
echo "usage: ${0##*/} extension ..." >&2
exit 1
fi
dir=./backup
mkdir -p "$dir"
# if the script is called like `script.sh foo bar baz`
# then $pattern is `@(*foo|*bar|*baz)`
pattern=$(
set -- "${@/#/*}"
IFS='|'
echo "@($*)"
)
shopt -s nocasematch
for file in *; do
# right-hand side is specifically unquoted
if [[ "$file" == $pattern ]]; then
read -p "Move file '$file'? [y/N] " ans
if [[ "$ans" == Y* ]]; then
mv -i -v "$file" "$dir"
fi
fi
done
課題なので、具体的な質問をする前に理解できない部分を少し調べてみてください。これバッシュマニュアル良い出発点です。