ユーザーの入力はスペースで区切って、これらの入力をカンマで区切るコマンドに入力する必要があります。

ユーザーの入力はスペースで区切って、これらの入力をカンマで区切るコマンドに入力する必要があります。

そのため、スペースで区切られた文字列または値を入力してから、値を1つずつ確認し、それを私が持っているコマンドの1つに必要な形式に変換するユーザーから入力を受け取ることを望んでいます。私は次のようなものが欲しい。

ユーザーは次のようなプロンプトを受け取ります。

Specify the package: perl runtime pool tools

私は4つの文字列だけを入力します。今私の出力については、次のようにしたいと思います。

Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools

Pkgはデフォルトでユーザーが入力した金額に基づいて1ずつ増加します。

可能ですか? Bashでどのようにこれを達成できますか?

どんな助けでも大変感謝します!時間をいただきありがとうございます!

答え1

最初メッセージを表示しない!データの入力を求めるのは良い考えではありません。間違えやすく、スペルが間違っていたり、コマンドを繰り返すことができず、ファイル名にタブ補完機能を使用できません。これは何の理由もなくユーザーとあなたの人生をより困難にするだけです。ユーザーにパッケージ名をパラメータとして渡すようにします。

#!/bin/bash

packageString="Pkg1=$1"
shift

for (( i=1; i<=$#;i++)); do
  packageString+=";Pkg"$((i+1))"=${!i}"
done
echo "$packageString";

質問への入力を使用して上記のスクリプトを実行すると、次の結果が表示されます。

$ foo.sh perl runtime pool tools
Pkg1=perl;Pkg2=runtime;Pkg3=pool;Pkg4=tools

答え2

私は鳴っています。テディンスの主張何の理由もなくユーザーに対話的にメッセージを表示しないでください。この場合、ユーザーはシェルのコマンドライン履歴からコマンドを呼び出すか、シェルのタブ補完、一般編集機能などを使用するオプションを提供するので、文字列をスクリプトに引数として簡単に提供できます。

次のスクリプトは単一のawkコマンドを使用します。

このawkコマンドは、与えられた文字列をコマンドライン引数として使用し、ループ内の各文字列の形式を個別に指定します。ループの目的は、それぞれ文字列であるフィールドレコードを作成することです。ここでPkgN=something、はN整数カウンタ、somethingは与えられた文字列の1つです。

ループが終了すると、レコードprint全体が出力されます。フィールド間には、に割り当てられた区切り文字がOFS使用されます。

#!/bin/sh

awk -v OFS=, '
BEGIN {
        for (i = 1; i < ARGC; ++i) $i = sprintf("Pkg%d=%s", i, ARGV[i])
        print
}' "$@"

同じアイデアですが、シェルループを使用します。

#!/bin/sh

i=0
for pkg do
    i=$(( i + 1 ))
    set -- "$@" "Pkg$i=$pkg"
    shift
done

IFS=,
printf '%s\n' "$*"

これにより、各位置引数(スクリプト引数)が新しい文字列に置き換えられ、すべてコンマが区切り文字として印刷されます。

引数が指定されていない場合、両方のスクリプトは空行を出力します。スクリプトの先頭でパラメータをテストし、パラメータがない場合は終了してこれを防ぐことができます。

[ "$#" -ne 0 ] || exit

ここでテストが実行される方法は、スクリプトが引数なしで呼び出されると、スクリプトがゼロ以外の終了状態で終了することを保証します。

テスト:

$ ./script perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools

答え3

script.sh次のコード(以下の例で命名)を含むスクリプトは、説明された出力を提供する必要があります。

#!/bin/bash

#USER INPUT
read -p "Specify the package: " -a vals

#COUNTER
i=1

#ARRAY ELEMENT LOOP
for v in "${vals[@]}"; do

   #Printing output  
   echo -n "Pkg$i=$v"

   #Increment counter and add the comma, or break out of loop if $i==
   i=$((i+1))
   if [[ $i -le ${#vals[@]} ]]; then
        echo -n ","
   else
        break
   fi

done

シェルでスクリプトを実行する前に、スクリプトを実行可能にしてchmodから()実行する必要があります。

chmod +x script.sh
./script.sh

入力/出力は次のとおりです。

Specify the package: perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools

答え4

$ perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' perl runtime pool tools
Pkg1=perl,Pkg2=runtime,Pkg3=pool,Pkg4=tools

map { "Pkg" . ++$i . "=$_" } @ARGVPkg$i各要素がリテラル文字列、カウンタ変数()(各ループで自動的にインクリメントされます)、およびリテラルシンボルがmap先頭にあるコマンドライン引数の1つであるリストを返します=perldoc -f map仕組みの詳細についてはをご覧ください。

リストは区切り文字でカンマで連結され、印刷されます。望むよりperldoc -f join

この-lオプションを使用すると、自動行末処理が可能になります。このスクリプトの場合、処理する標準入力がないため、これはすべての文がprint自動的に改行文字を出力することを意味します(通常、Perlはprint明示的に含めない限り改行文字を出力しません)。表示man perlrunと検索-l\[octnum\]


ユーザー入力を最初に受け入れるには(他の人が指摘したように、ユーザーにとって非常に迷惑で不便なので、お勧めできません)、次のようにすることができます。

#!/bin/bash

# read the user input into array variable "$input"
read -p "Specify the package: " -r -a input

# now pass the array to the perl one-liner
perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' -- "${input[@]}"

これは--、ユーザーが誤って(または悪意を持って)perlコマンドラインオプションなどを入力した場合、perlがユーザー入力をオプションとして解釈するのを防ぎます-e ';system("rm -rf /");'。ユーザーが入力した入力を絶対に信頼しないでください。

そして、通常どおりPerlスクリプトの出力を別のシェル変数としてキャプチャする必要がある場合は、次のようにします。コマンドの置き換え:

var=$(perl -le 'print join ",", map { "Pkg" . ++$i . "=$_" } @ARGV' -- "${input[@]}")
printf "%s\n" "$var"

関連情報