SHELL:出力が予想したものとは異なります。

SHELL:出力が予想したものとは異なります。

私は次の課題を実行しており、私のプログラムに関する質問があります。

以下の説明に従ってファイルをコピーするシェルスクリプトを作成します。サフィックスはコマンドライン引数として送信する必要があります。指定されたサフィックスが適切な現在のディレクトリ内の各ファイルについて、ユーザーにそのファイルを保存する必要があるかどうかを尋ねるメッセージが表示されます。答えが「はい」の場合は、ファイルをバックアップディレクトリにコピーする必要があります。ディレクトリが存在しない場合は、新規作成する必要があります。

これが私がしたことです:

#!/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

課題なので、具体的な質問をする前に理解できない部分を少し調べてみてください。これバッシュマニュアル良い出発点です。

関連情報