그래서 공백으로 구분된 문자열이나 값을 입력한 다음 값을 하나씩 확인하고 이를 내가 가지고 있는 명령 중 하나에 필요한 형식으로 변환하는 사용자로부터 입력을 받을 수 있기를 원합니다. 나는 다음과 같은 것을 원합니다.
사용자는 다음과 유사한 프롬프트를 받게 됩니다.
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
는 주어진 문자열 중 하나입니다.
루프가 끝나면 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
여기서 테스트가 수행되는 방식은 스크립트가 인수 없이 호출되는 경우 스크립트가 0이 아닌 종료 상태로 종료되도록 보장합니다.
시험:
$ ./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
앞에 붙은 명령줄 인수 중 하나 인 목록을 반환합니다 =
. 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"