명령 대체가 변수 대체 내에 중첩될 수 있습니까?

명령 대체가 변수 대체 내에 중첩될 수 있습니까?

명령을 통해 액세스되는 특정 문자열에 대해 변수 대체를 사용하고 싶습니다. 예를 들어 클립보드에 복사한 내용을 다음과 같이 접근할 수 있습니다.

$ xclip -o -selection clipboard
Here's a string I just copied.

변수에 할당하면 변수 대체를 수행할 수 있습니다.

$ var=$(xclip -o -selection clipboard)
$ echo $var
Here's a string I just copied.
$ echo ${var/copi/knott}
Here's a string I just knotted.

그런데 변수에 할당하지 않고 변수 대체를 수행할 수 있는 방법이 있습니까? 개념적으로는 이렇습니다.

$ echo ${$(xclip -o -selection clipboard)/copi/knott}
bash: ${$(xclip -o -selection clipboard)/copi/knott}: bad substitution

var문자열이 아닌 변수 이름이 필요하기 때문에 이 구문은 실패합니다 .

답변1

아니 당신은 할 수 없습니다. bash대부분의 다른 쉘( zsh제외

그것으로 zsh당신은 할 수 있습니다중첩 교체:

$ echo ${$(echo 123)/123/456}   
456

답변2

예, 그렇게 할 수 있습니다. 정말 예쁘지 않아요. 그것은 더 비슷하다대기줄중첩된 것보다. 문제는 확장된 매개변수의 값을 조작해야 한다는 것입니다. 매개변수에 값이 없으면 많은 작업을 수행할 수 없습니다. 따라서 값을 할당할 수 있습니다.하지만확장하면 지름길이 아닙니다.

v=; echo "${v:=${0##*["$0${v:=$(xsel -bo)}"]}${v/copi/knott}}"

$0체인 내에서 매개변수 확장을 사용하여숨다분배하다. 중첩 할당 확장 내에서 var 값을 할당합니다. 외부 우선 - 그러나 내부적으로 수행되는 모든 작업에만 확장되므로 말하기가 어렵습니다. 그러나 내부 확장을 침묵시킨 다음 수정하면 원하는 것을 얻을 수 있습니다. 문자열을 클립보드에 복사한 후(난 안 그랬어 xclip- 그냥 xsel)다음과 같이 인쇄됩니다.

Here's a string I just knotted.

그러나 이를 생략하면 어떤 일이 발생하는지 더 명확해집니다 $0.

v=; echo "${v:=${v:=$(xsel -bo)}${v/copi/knott}}"

인쇄:

Here's a string I just copied.  Here's a string I just knotted.

...내부 할당은 수정 전에 발생하기 때문에 위에서 언급한 것처럼 외부 할당이 우선하며 내부 할당의 확장까지 확장됩니다.그리고내부 확장을 수정했습니다.

물론, 타겟 매개변수가이미할당 - 따라서 변수를 먼저 지운 경우에만 이 작업을 수행할 수 있습니다. 솔직히 할당하기에 가장 편리한 시간일 것입니다.

답변3

다음은 연결된 매개변수 대체를 위해 임시 변수 할당을 우회하는 해킹의 예입니다.

declare -a values=( "4: " "#1" "#2" "#3" "#4" )
declare -A arr["VALUES"]="${values[@]}"

echo -e "Original: ${arr[@]}"

"${arr[@]#*: ?}" >&/dev/null; san="${_//#/}"

echo -e "Sanitized: $san"

설명하다:

arrarray 의 값으로 연관 배열을 초기화 합니다 values. 첫 번째 요소에는 값 요소의 수, :필터링해야 하는 ; 및 #모든 값의 접두사가 포함됩니다.

"${arr[@]#*: ?}" >&/dev/null

이는 값을 먼저 확장하고 ( ) arr까지 이전의 모든 항목을 필터링하여 합계 결과를 삭제하는 매개변수 대체입니다 . 이는 결과 변수 할당 누락으로 인해 발생하는 오류도 억제합니다.'4: '#*: ?stdoutstderr

>&출력 ( )을 ( ) 에 할당 하고 둘 다에 할당 2>&1하는 약어입니다 .stderrfd2stdoutfd1/dev/null

이제 비결은 bash의 특수 밑줄 _인수를 사용하여 이전 명령(위의 첫 번째 인수 확장 작업 및 결과 리디렉션 /dev/null)에서 버려진 결과 인수를 두 번째 인수 대체에 복사하는 것입니다. 여기서 #접두사 값이 필터링됩니다.

san="${_//#/}"

산출:

원본: 4: #1#2#3#4

소독 : 1 2 3 4

또한보십시오:특수 매개변수 및 쉘 변수

답변4

Linux에서는 소스 명령을 파이프할 수 있습니다.

echo $(xclip -o -selection clipboard)/copi/knott|source /dev/stdin

그렇지 않은 시스템의 경우 /dev/stdin먼저 임시 파일에 쓴 다음 해당 파일에 써야 합니다 source.

관련 정보