70

について助けが必要getoptsです。

実行すると次のようになる Bash スクリプトを作成しました。

$ foo.sh -i env -d ディレクトリ -s サブディレクトリ -f ファイル

各フラグから 1 つの引数を処理する場合、正しく機能します。しかし、各フラグから複数の引数を呼び出すと、複数の変数情報を の変数から引き出す方法がわかりませんgetopts

while getopts ":i:d:s:f:" opt
   do
     case $opt in
        i ) initial=$OPTARG;;
        d ) dir=$OPTARG;;
        s ) sub=$OPTARG;;
        f ) files=$OPTARG;;

     esac
done

オプションを取得した後、変数からディレクトリ構造を構築したい

foo.sh -i test -d directory -s subdirectory -s subdirectory2 -f file1 file2 file3

次に、ディレクトリ構造は次のようになります

/test/directory/subdirectory/file1
/test/directory/subdirectory/file2
/test/directory/subdirectory/file3
/test/directory/subdirectory2/file1
/test/directory/subdirectory2/file2
/test/directory/subdirectory2/file3

何か案は?

4

11 に答える 11

27

この質問が古いことは知っていますが、誰かが答えを探しに来た場合に備えて、この答えをここに投げたいと思いました.

BASH のようなシェルは、すでにこのようにディレクトリを再帰的に作成することをサポートしているため、スクリプトは実際には必要ありません。たとえば、元のポスターは次のようなものを求めていました。

$ foo.sh -i test -d directory -s subdirectory -s subdirectory2 -f file1 file2 file3
/test/directory/subdirectory/file1
/test/directory/subdirectory/file2
/test/directory/subdirectory/file3
/test/directory/subdirectory2/file1
/test/directory/subdirectory2/file2
/test/directory/subdirectory2/file3

これは、次のコマンド ラインで簡単に実行できます。

pong:~/tmp
[10] rmclean$ mkdir -pv test/directory/{subdirectory,subdirectory2}/{file1,file2,file3}
mkdir: created directory ‘test’
mkdir: created directory ‘test/directory’
mkdir: created directory ‘test/directory/subdirectory’
mkdir: created directory ‘test/directory/subdirectory/file1’
mkdir: created directory ‘test/directory/subdirectory/file2’
mkdir: created directory ‘test/directory/subdirectory/file3’
mkdir: created directory ‘test/directory/subdirectory2’
mkdir: created directory ‘test/directory/subdirectory2/file1’
mkdir: created directory ‘test/directory/subdirectory2/file2’
mkdir: created directory ‘test/directory/subdirectory2/file3’

またはもう少し短い:

pong:~/tmp
[12] rmclean$ mkdir -pv test/directory/{subdirectory,subdirectory2}/file{1,2,3}
mkdir: created directory ‘test’
mkdir: created directory ‘test/directory’
mkdir: created directory ‘test/directory/subdirectory’
mkdir: created directory ‘test/directory/subdirectory/file1’
mkdir: created directory ‘test/directory/subdirectory/file2’
mkdir: created directory ‘test/directory/subdirectory/file3’
mkdir: created directory ‘test/directory/subdirectory2’
mkdir: created directory ‘test/directory/subdirectory2/file1’
mkdir: created directory ‘test/directory/subdirectory2/file2’
mkdir: created directory ‘test/directory/subdirectory2/file3’

またはより短く、より適合性があります:

pong:~/tmp
[14] rmclean$ mkdir -pv test/directory/subdirectory{1,2}/file{1,2,3}
mkdir: created directory ‘test’
mkdir: created directory ‘test/directory’
mkdir: created directory ‘test/directory/subdirectory1’
mkdir: created directory ‘test/directory/subdirectory1/file1’
mkdir: created directory ‘test/directory/subdirectory1/file2’
mkdir: created directory ‘test/directory/subdirectory1/file3’
mkdir: created directory ‘test/directory/subdirectory2’
mkdir: created directory ‘test/directory/subdirectory2/file1’
mkdir: created directory ‘test/directory/subdirectory2/file2’
mkdir: created directory ‘test/directory/subdirectory2/file3’

または最後に、シーケンスを使用して:

pong:~/tmp
[16] rmclean$ mkdir -pv test/directory/subdirectory{1..2}/file{1..3}
mkdir: created directory ‘test’
mkdir: created directory ‘test/directory’
mkdir: created directory ‘test/directory/subdirectory1’
mkdir: created directory ‘test/directory/subdirectory1/file1’
mkdir: created directory ‘test/directory/subdirectory1/file2’
mkdir: created directory ‘test/directory/subdirectory1/file3’
mkdir: created directory ‘test/directory/subdirectory2’
mkdir: created directory ‘test/directory/subdirectory2/file1’
mkdir: created directory ‘test/directory/subdirectory2/file2’
mkdir: created directory ‘test/directory/subdirectory2/file3’
于 2012-05-30T14:10:21.050 に答える
25

getoptsオプションは、0個または1個の引数のみを取ることができます。インターフェイスを変更して-fオプションを削除し、残りの非オプション引数を繰り返し処理することをお勧めします。

usage: foo.sh -i end -d dir -s subdir file [...]

それで、

while getopts ":i:d:s:" opt; do
  case "$opt" in
    i) initial=$OPTARG ;;
    d) dir=$OPTARG ;;
    s) sub=$OPTARG ;;
  esac
done
shift $(( OPTIND - 1 ))

path="/$initial/$dir/$sub"
mkdir -p "$path"

for file in "$@"; do
  touch "$path/$file"
done
于 2011-09-23T14:10:22.637 に答える
13

私はあなたがこのように持っていたのと同じ問題を修正しました:

それ以外の:

foo.sh -i test -d directory -s subdirectory -s subdirectory2 -f file1 file2 file3

これを行う:

foo.sh -i test -d directory -s "subdirectory subdirectory2" -f "file1 file2 file3"

スペースセパレーターを使用すると、基本的なループでスペースセパレーターを実行できます。コードは次のとおりです。

while getopts ":i:d:s:f:" opt
   do
     case $opt in
        i ) initial=$OPTARG;;
        d ) dir=$OPTARG;;
        s ) sub=$OPTARG;;
        f ) files=$OPTARG;;

     esac
done

for subdir in $sub;do
   for file in $files;do
      echo $subdir/$file
   done   
done

出力例は次のとおりです。

$ ./getopts.sh -s "testdir1 testdir2" -f "file1 file2 file3"
testdir1/file1
testdir1/file2
testdir1/file3
testdir2/file1
testdir2/file2
testdir2/file3
于 2011-12-28T15:54:09.420 に答える
2

元の質問は getopts を扱っていますが、getopts なしでより柔軟な機能を提供する別のソリューションがあります (これはおそらくもう少し冗長ですが、はるかに柔軟なコマンド ライン インターフェイスを提供します)。次に例を示します。

while [[ $# > 0 ]]
do
    key="$1"
    case $key in
        -f|--foo)
            nextArg="$2"
            while ! [[ "$nextArg" =~ -.* ]] && [[ $# > 1 ]]; do
                case $nextArg in
                    bar)
                        echo "--foo bar found!"
                    ;;
                    baz)
                        echo "--foo baz found!"
                    ;;
                    *)
                        echo "$key $nextArg found!"
                    ;;
                esac
                if ! [[ "$2" =~ -.* ]]; then
                    shift
                    nextArg="$2"
                else
                    shift
                    break
                fi
            done
        ;;
        -b|--bar)
            nextArg="$2"
            while ! [[ "$nextArg" =~ -.* ]] && [[ $# > 1 ]]; do
                case $nextArg in
                    foo)
                        echo "--bar foo found!"
                    ;;
                    baz)
                        echo "--bar baz found!"
                    ;;
                    *)
                        echo "$key $nextArg found!"
                    ;;
                esac
                if ! [[ "$2" =~ -.* ]]; then
                    shift
                    nextArg="$2"
                else
                    shift
                    break
                fi
            done
        ;;
        -z|--baz)
            nextArg="$2"
            while ! [[ "$nextArg" =~ -.* ]] && [[ $# > 1 ]]; do

                echo "Doing some random task with $key $nextArg"

                if ! [[ "$2" =~ -.* ]]; then
                    shift
                    nextArg="$2"
                else
                    shift
                    break
                fi
            done
        ;;
        *)
            echo "Unknown flag $key"
        ;;
    esac
    shift
done

この例では、受け入れられたコマンド ライン フラグ (-f や --foo など) に一致するパラメーターを探して、すべてのコマンド ライン オプションをループしています。フラグが見つかったら、パラメーターがなくなるか、別のフラグに遭遇するまで、すべてのパラメーターをループします。これにより、フラグのみを処理する外側のループに戻ります。

このセットアップでは、次のコマンドは同等です。

script -f foo bar baz
script -f foo -f bar -f baz
script --foo foo -f bar baz
script --foo foo bar -f baz

次のような非常にまとまりのないパラメーター セットを解析することもできます。

script -f baz derp --baz herp -z derp -b foo --foo bar -q llama --bar fight

出力を取得するには:

--foo baz found!
-f derp found!
Doing some random task with --baz herp
Doing some random task with -z derp
--bar foo found!
--foo bar found!
Unknown flag -q
Unknown flag llama
--bar fight found!
于 2016-09-28T18:21:17.877 に答える
0

リストを作成する方法を示していないため

/test/directory/subdirectory/file1
. . .
test/directory/subdirectory2/file3

続行する方法は少し不明確ですが、基本的には適切な変数に新しい値を追加し続ける必要があります。

 case $opt in
    d ) dirList="${dirList} $OPTARG" ;;
 esac

最初のパスでは dir が空になり、最終的な値の from にスペースが入ることに注意してください${dirList}。(前後に余分なスペースを一切含まないコードが本当に必要な場合は、お見せできるコマンドがありますが、理解するのは難しく、ここでは必要ないようです。しかし、私に知らせてください)

次に、リスト変数を for ループでラップして、すべての値を出力できます。

for dir in ${dirList} do
   for f in ${fileList} ; do
      echo $dir/$f
   done
done

最後に、不明な入力を case ステートメントに「トラップ」することをお勧めします。つまり、

 case $opt in
    i ) initial=$OPTARG;;
    d ) dir=$OPTARG;;
    s ) sub=$OPTARG;;
    f ) files=$OPTARG;;
    * ) 
       printf "unknown flag supplied "${OPTARG}\nUsageMessageGoesHere\n"
       exit 1
    ;;

 esac 

これが役立つことを願っています。

于 2011-09-23T13:58:28.633 に答える