Bash 인수에서 따옴표를 유지하는 방법은 무엇입니까?
전달 된 인수에 따옴표를 유지하려는 Bash 스크립트가 있습니다.
예:
./test.sh this is "some test"
그런 다음 해당 인수를 사용하고 전체 인수 목록 주위에 따옴표와 따옴표를 포함하여 다시 사용하고 싶습니다.
을 사용해 보았지만 \"$@\"
목록 안의 따옴표가 제거됩니다.
어떻게해야합니까?
큰 따옴표로 문자열을 작은 따옴표로 묶으십시오.
./test.sh this is '"some test"'
따라서 작은 따옴표 안의 큰 따옴표도 문자열로 해석되었습니다.
그러나 작은 따옴표 사이에 전체 문자열을 넣는 것이 좋습니다.
./test.sh 'this is "some test" '
셸이 수행하는 작업을 이해하거나 스크립트에서 인수를 해석하기 위해 다음과 같은 작은 스크립트를 작성할 수 있습니다.
#!/bin/bash
echo $@
echo "$@"
그런 다음 다른 문자열로 스크립트를 호출 할 때 무슨 일이 일어나는지보고 테스트합니다.
using "$@"
은 인수를 공백으로 다시 분할하지 않고 목록으로 대체합니다 (셸 스크립트가 호출 될 때 한 번 분할 됨). 일반적으로 인수를 다른 프로그램에 다시 전달하려는 경우 정확히 원하는 것입니다.
무엇을하려고하고 어떤 방식으로 작동하지 않습니까?
Yuku의 대답은 스크립트의 유일한 사용자 인 경우에만 작동하는 반면 Dennis Williamson은 주로 문자열 인쇄에 관심이 있고 따옴표가 없을 것으로 예상하는 경우 유용합니다.
다음은 모든 인수를 하나의 큰 인용 문자열 인수로 또는 -c
매개 변수에 전달하려는 경우 사용할 수있는 버전입니다 .bash
su
#!/bin/bash
C=''
for i in "$@"; do
i="${i//\\/\\\\}"
C="$C \"${i//\"/\\\"}\""
done
bash -c "$C"
따라서 모든 인수는 주위에 따옴표를 붙입니다 (이 목적을 위해 이전에 없었던 경우 무해합니다). 그러나 이스케이프를 이스케이프 한 다음 인수에 이미있는 모든 따옴표를 이스케이프합니다 (구문 ${var//from/to}
은 전역 하위 문자열 대체를 수행함). .
물론 이미 공백이있는 항목 만 인용 할 수 있지만 여기서는 중요하지 않습니다. 이와 같은 스크립트의 한 가지 유틸리티는 미리 정의 된 특정 환경 변수 집합을 가질 수 있다는 것입니다 (또는 su를 사용하여 모든 것을 큰 따옴표로 묶지 않고 특정 사용자로 항목을 실행).
업데이트 : 최근에 최소한의 포크로 POSIX 방식으로이 작업을 수행해야하는 이유가 있었는데,이 스크립트로 이어지는 것입니다 (마지막 printf는 스크립트를 호출하는 데 사용되는 명령 줄을 출력합니다.이 스크립트를 호출하려면 복사-붙여 넣기 할 수 있어야합니다.) 동등한 인수와 함께) :
#!/bin/sh
C=''
for i in "$@"; do
case "$i" in
*\'*)
i=`printf "%s" "$i" | sed "s/'/'\"'\"'/g"`
;;
*) : ;;
esac
C="$C '$i'"
done
printf "$0%s\n" "$C"
''
쉘 은 따옴표 $
와 같은 것을 해석 하기 때문에 전환했습니다 .!!
""
공백을 포함하는 인수가 반드시 인용되어야한다고 가정하는 것이 안전하다면 다음과 같이 추가 할 수 있습니다.
#!/bin/bash
whitespace="[[:space:]]"
for i in "$@"
do
if [[ $i =~ $whitespace ]]
then
i=\"$i\"
fi
echo "$i"
done
다음은 샘플 실행입니다.
$ ./argtest abc def "ghi jkl" $'mno\tpqr' $'stu\nvwx'
abc
def
"ghi jkl"
"mno pqr"
"stu
vwx"
당신은 또한 수 삽입 하여 문자 탭과 줄 바꿈 Ctrl- V Tab및 Ctrl- V Ctrl- J대신 내 탈출을 사용하여 이중 또는 단일 따옴표 $'...'
.
Bash에서 문자 삽입 에 대한 참고 사항 : Bash에서 Vi 키 바인딩 ( set -o vi
)을 사용하는 경우 (Emacs가 기본값 인- set -o emacs
), 문자를 삽입하려면 삽입 모드 에 있어야합니다 . Emacs 모드에서는 항상 삽입 모드에 있습니다.
이를 수행하는 두 가지 안전한 방법이 있습니다.
1. 쉘 매개 변수 확장 :${variable@Q}:
다음을 통해 변수를 확장 할 때 ${variable@Q}
:
확장은 입력으로 재사용 할 수있는 형식으로 인용 된 매개 변수의 값인 문자열입니다.
예:
$ expand-q() { for i; do echo ${i@Q}; done; } # Same as for `i in "$@"`...
$ expand-q word "two words" 'new
> line' "single'quote" 'double"quote'
word
'two words'
$'new\nline'
'single'\''quote'
'double"quote'
2. printf %q "$quote-me"
printf
내부 인용을 지원합니다. 에 대한 설명서 항목printf
은 다음과 같습니다.
%q
printf가 쉘 입력으로 재사용 할 수있는 형식으로 해당 인수를 출력하도록합니다.
예:
$ cat test.sh
#!/bin/bash
printf "%q\n" "$@"
$
$ ./test.sh this is "some test" 'new
>line' "single'quote" 'double"quote'
this
is
some\ test
$'new\nline'
single\'quote
double\"quote
$
두 번째 방법은 인용 된 텍스트를 사람에게 표시하는 경우 약간 더 깔끔합니다.
관련 : bash, POSIX sh 및 zsh의 경우 : 백 슬래시가 아닌 작은 따옴표가있는 따옴표 문자열
Tom Hale이 말했듯이이를 수행하는 한 가지 방법은 quote-escape 를 printf
사용 %q
하는 것입니다.
예를 들면 :
send_all_args.sh
#!/bin/bash
if [ "$#" -lt 1 ]; then
quoted_args=""
else
quoted_args="$(printf " %q" "${@}")"
fi
bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_args}"
send_fewer_args.sh
#!/bin/bash
if [ "$#" -lt 2 ]; then
quoted_last_args=""
else
quoted_last_args="$(printf " %q" "${@:2}")"
fi
bash -c "$( dirname "${BASH_SOURCE[0]}" )/receiver.sh${quoted_last_args}"
receiver.sh
#!/bin/bash
for arg in "$@"; do
echo "$arg"
done
사용 예 :
$ ./send_all_args.sh
$ ./send_all_args.sh a b
a
b
$ ./send_all_args.sh "a' b" 'c "e '
a' b
c "e
$ ./send_fewer_args.sh
$ ./send_fewer_args.sh a
$ ./send_fewer_args.sh a b
b
$ ./send_fewer_args.sh "a' b" 'c "e '
c "e
$ ./send_fewer_args.sh "a' b" 'c "e ' 'f " g'
c "e
f " g
I needed this for forwarding all arguments to another interpreter. What ended up right for me is:
bash -c "$(printf ' %q' "$@")"
Example (when named as forward.sh):
$ ./forward.sh echo "3 4"
3 4
$ ./forward.sh bash -c "bash -c 'echo 3'"
3
(Of course the actual script I use is more complex, involving in my case nohup and redirections etc., but this is the key part.)
My problem was similar and I used mixed ideas posted here.
We have a server with a PHP script that sends e-mails. And then we have a second server that connects to the 1st server via SSH and executes it.
The script name is the same on both servers and both are actually executed via a bash script.
On server 1 (local) bash script we have just:
/usr/bin/php /usr/local/myscript/myscript.php "$@"
This resides on /usr/local/bin/myscript
and is called by the remote server. It works fine even for arguments with spaces.
But then at the remote server we can't use the same logic because the 1st server will not receive the quotes from "$@"
. I used the ideas from JohnMudd and Dennis Williamson to recreate the options and parameters array with the quotations. I like the idea of adding escaped quotations only when the item has spaces in it.
So the remote script runs with:
CSMOPTS=()
whitespace="[[:space:]]"
for i in "$@"
do
if [[ $i =~ $whitespace ]]
then
CSMOPTS+=(\"$i\")
else
CSMOPTS+=($i)
fi
done
/usr/bin/ssh "$USER@$SERVER" "/usr/local/bin/myscript ${CSMOPTS[@]}"
Note that I use "${CSMOPTS[@]}"
to pass the options array to the remote server.
Thanks for eveyone that posted here! It really helped me! :)
Changed unhammer's example to use array.
printargs() { printf "'%s' " "$@"; echo; }; # http://superuser.com/a/361133/126847
C=()
for i in "$@"; do
C+=("$i") # Need quotes here to append as a single array element.
done
printargs "${C[@]}" # Pass array to a program as a list of arguments.
Quotes are interpreted by bash and are not stored in command line arguments or variable values.
If you want to use quoted arguments, you have to quote them each time you use them:
val="$3"
echo "Hello World" > "$val"
Just use:
"${@}"
For example:
# cat t2.sh
for I in "${@}"
do
echo "Param: $I"
done
# cat t1.sh
./t2.sh "${@}"
# ./t1.sh "This is a test" "This is another line" a b "and also c"
Param: This is a test
Param: This is another line
Param: a
Param: b
Param: and also c
Yes, seems that it is not possible to ever preserve the quotes, but for the issue I was dealing with it wasn't necessary.
I have a bash function that will search down folder recursively and grep for a string, the problem is passing a string that has spaces, such as "find this string". Passing this to the bash script will then take the base argument $n and pass it to grep, this has grep believing these are different arguments. The way I solved this by using the fact that when you quote bash to call the function it groups the items in the quotes into a single argument. I just needed to decorate that argument with quotes and pass it to the grep command.
If you know what argument you are receiving in bash that needs quotes for its next step you can just decorate with with quotes.
As Gary S. Weaver shown in his source code tips, the trick is to call bash with parameter '-c' and then quote the next.
e.g.
bash -c "<your program> <parameters>"
or
docker exec -it <my docker> bash -c "$SCRIPT $quoted_args"
If you need to pass all arguments to bash from another programming language (for example, if you'd want to execute bash -c
or emit_bash_code | bash
), use this:
- escape all single quote characters you have with
'\''
. - then, surround the result with singular quotes
The argument of abc'def
will thus be converted to 'abc'\''def'
. The characters '\''
are interpreted as following: the already existing quoting is terminated with the first first quote, then the escaped singular single quote \'
comes, then the new quoting starts.
참고URL : https://stackoverflow.com/questions/1668649/how-to-keep-quotes-in-bash-arguments
'program story' 카테고리의 다른 글
입력 유형 = 파일을 만드는 방법은 pdf 및 xls 만 허용해야합니다. (0) | 2020.11.03 |
---|---|
% 0 | % 0이란 무엇이며 어떻게 작동합니까? (0) | 2020.11.03 |
git 후크에서 현재 작업 디렉토리가 git 저장소 내에 있음을 보장합니까? (0) | 2020.11.02 |
Microsoft.Net.Compilers의 목적은 무엇입니까? (0) | 2020.11.02 |
특정 페이지에서 사용 된 CSS 만 추출 (0) | 2020.11.02 |