whileループでユーザーにファイルの種類を尋ねる

whileループでユーザーにファイルの種類を尋ねる

スクリプトを調整して、ユーザーに特定の種類のファイルを要求するようにしています。入力されたファイルが特定のファイルの種類と一致しない場合は、while ループに入り、ユーザーが正しいファイルを入力するまで繰り返します。

この場合、ユーザーに次.zipのファイルの提供を要求します。

read -p "Enter zip file: " package1
 while [ package1 != *.zip ] ; do
     read -p "Please enter file ending in '.zip': " package1
 done <<< package1
echo $package1

これまではエラーが発生していました。今は、空白のカーソルが表示されるだけで、出力はありません。入力しても*.zipしなくても、空白のカーソルが表示され、出力もされないまま次の行に進みます。

ご意見は?

編集:

わかりました。ループを使用することにしました。この場合selectよりもはるかに良い選択肢です。while

しかし、そのzipファイル (またはプロンプトで表示された任意のファイル タイプ) が他のディレクトリにある可能性がある場合はどうなるでしょうか。シェル内でディレクトリを変更するオプションを提供したいと思いますselect-loop

これまで試したこと:

echo Select zip file:
                options=(".." *.zip)
                select package1 in "${options[@]}" ; do
                        case $package1 in
                                1 ) cd ..; echo Select zip file: ;;
                                # Different Directory ) ;;
                                * ) break ;;
                        esac
                done

しかし、ディレクトリを変更した後、ループはメニュー項目を再表示しません。ユーザーが望む場合cd以外にまったく異なるパスを提供する方法や、../

"All other existing \# file items" ) ... ; break;;

の中にcase

答え1

最後の拡張子だけを調べることで論理的に簡単になります。

while [ "${package1##*.}" != "zip" ]
do
    read -e -p "Specify a .zip file: " package1
done
echo $package1

答え2

より洗練された解決策が投稿されていますが、元のスクリプトが失敗する原因となっているいくつかのエラーとその修正方法を指摘することが重要だと思います。

まず、while ループ内で変数をテストする場合、その変数に格納されている実際のデータを読み取るために、その変数の前にpackage1を置く必要があります。$

次に、 whileループテストで[[...]]の代わりに を使用します。[...]これにより、ワイルドカードを使用してパターンマッチングを行うことができます*。ただし、これは bash でのみ機能し、sh では機能しません。これ[[...]]versusの使用に関する詳細な説明については、回答を参照してください[...]

<<< package1最後に、 while ループの最後に文字列を渡す必要はありません。

意図したとおりに動作するスクリプトの修正バージョンを以下に示します。

#!/bin/bash

read -p "Enter zip file: " package1
while [[ "$package1" != *.zip ]]; do
    read -p "Please enter file ending in '.zip': " package1
    done 
echo $package1

答え3

ユーザーにファイルのパス名を対話的に入力させないでください。スクリプトのコマンド ラインで Zip アーカイブ ファイルのパス名を使用してスクリプトを呼び出す方が簡単です。これにより、シェルのファイル名補完機能とファイル名グロブ パターンを使用できるようになります。

スクリプトは次のように呼び出されます。

./myscript /some/path/myarchive.zip

または

./myscript folder/archive-*.zip

または類似。

スクリプトでは、

#!/bin/bash

for archive_path do
    printf 'Processing archive "%s"...\n' "$archive_path"

   # code to process "$archive_path" goes here
done

スクリプト内のループは、スクリプトに渡されたすべての引数をループし、各反復では、"$archive_path"スクリプトに渡された個々のアーカイブのパス名になります。

ファイル名が特定の文字列で終わるかどうかを確認する必要はありません。"$archive_path"アーカイブで使用するツールはファイル名のサフィックスを気にしない可能性があるからです。もし気にするのであれば、適切な終了コードで失敗しますが、これは簡単にキャッチできます。

if ! unzip "$archive_path"; then
    printf 'Failed to run unzip on "%s"\n' "$archive_path" >&2
    exit 1
fi

set -eスクリプト内で を使用する場合(おそらく最初のステートメントとして)、任意のコマンド (条件ステートメントの一部ではない) がゼロ以外の終了コードを返すと、スクリプトは自動的に終了します。

set -e

# The following would terminate the script if it failed:
unzip "$archive_path"

追加された「編集」について: ここで行っていることは、Zip アーカイブを選択するためのファイル ブラウザー ツールまたはファイル マネージャーの実装を開始することです。このコードを実際に何に使用したいかによって、これはやり過ぎかもしれません。

答え4

ユーザーに選択させたい場合既存 ファイルの場合、ユーザーが正確には知らないファイル名を記述するのではなく、リストから選択できるようにするために、selectの代わりにを使用します。read

select package1 in *.zip; do
    break;
done
echo "$package1"

ユーザーにはリストが表示され、番号を入力します。

関連情報