そのため、スペースで区切られた文字列または値を入力してから、値を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 . "=$_" } @ARGV
Pkg
$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"