변수에서 문자를 제거하는 가장 짧은 방법

변수에서 문자를 제거하는 가장 짧은 방법

변수에서 문자를 제거하는 방법에는 여러 가지가 있습니다.

지금까지 내가 찾은 가장 짧은 방법은 다음과 같습니다.tr:

OUTPUT=a\'b\"c\`d_123and_a_lot_more
OUTPUT=$(echo "$OUTPUT"|tr -d "'\`\"")
echo $OUTPUT

더 빠른 방법이 있나요?

'이 인용문은 , 및 그 자체와 "같은 인용문에 안전한가요 `?

답변1

보자. 내가 생각할 수 있는 가장 짧은 것은 솔루션을 적용한 것입니다 tr.

OUTPUT="$(tr -d "\"\`'" <<<$OUTPUT)"

다른 대안에는 이미 언급된 변수 대체가 포함되며, 이는 지금까지 표시된 것보다 짧을 수 있습니다.

OUTPUT="${OUTPUT//[\'\"\`]}"

물론 sed이것은 문자 측면에서 더 길다.

OUTPUT="$(sed s/[\'\"\`]//g <<<$OUTPUT)"

최소 길이를 의미하는지, 최소 시간을 의미하는지 잘 모르겠습니다. 길이 측면에서 이러한 특정 문자를 제거하면 이 두 문자가 가능한 가장 짧습니다(또는 내가 얻을 수 있는 모든 것). 그렇다면 어느 것이 가장 빠른가요? 변수를 예제의 변수로 설정 하여 OUTPUT테스트했지만 수십 번 반복했습니다.

$ echo ${#OUTPUT} 
4900

$ time tr -d "\"\`'" <<<$OUTPUT
real    0m0.002s
user    0m0.004s
sys     0m0.000s
$ time sed s/[\'\"\`]//g <<<$OUTPUT
real    0m0.005s
user    0m0.000s
sys     0m0.000s
$ time echo ${OUTPUT//[\'\"\`]}
real    0m0.027s
user    0m0.028s
sys     0m0.000s

보시다시피, tr분명히 가장 빠르고 그 다음이 입니다 sed. 또한 echo실제로는 다음을 사용하는 것보다 약간 더 빠른 것 같습니다 <<<.

$ for i in {1..10}; do 
    ( time echo $OUTPUT | tr -d "\"\`'" > /dev/null ) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0025
$ for i in {1..10}; do 
    ( time tr -d "\"\`'" <<<$OUTPUT > /dev/null ) 2>&1 
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0029

차이가 작았기 때문에 두 테스트 모두에 대해 위의 테스트를 10번 실행한 결과 가장 빠른 테스트는 실제로 시작해야 하는 테스트라는 것을 알았습니다.

echo $OUTPUT | tr -d "\"\`'" 

그러나 변수에 할당하는 오버헤드를 고려하면 상황이 달라집니다. 여기서 사용은 tr단순 교체보다 약간 느립니다.

$ for i in {1..10}; do
    ( time OUTPUT=${OUTPUT//[\'\"\`]} ) 2>&1
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0032

$ for i in {1..10}; do
    ( time OUTPUT=$(echo $OUTPUT | tr -d "\"\`'")) 2>&1
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0044

그래서 요약하자면, 결과만 보고 싶을 때 사용하고, tr변수에 다시 할당하고 싶을 때는 별도의 서브셸을 실행하는 오버헤드를 피하기 때문에 셸의 문자열 조작 기능을 사용하는 것이 더 빠릅니다.

답변2

당신이 사용할 수있는변수 대체:

$ OUTPUT=a\'b\"c\`d
$ echo "$OUTPUT"
a'b"c`d

다음 구문을 사용하십시오. ${parameter//pattern/string}패턴의 모든 항목을 문자열로 바꾸십시오.

$ echo "${OUTPUT//\'/x}"
axb"c`d
$ echo "${OUTPUT//\"/x}"
a'bxc`d
$ echo "${OUTPUT//\`/x}"
a'b"cxd
$ echo "${OUTPUT//[\'\"\`]/x}"
axbxcxd

답변3

Bash 또는 zsh에서는 다음과 같습니다.

OUTPUT="${OUTPUT//[\`\"\']/}"

이 패턴의 모든 인스턴스 가 ${VAR//PATTERN/}삭제됩니다. 더 많은 정보를 알고 싶다면Bash 매개변수 확장

이 솔루션은 외부 프로그램 실행을 포함하지 않으므로 짧은 문자열의 경우 가장 빠릅니다. 그러나 매우 긴 문자열의 경우 그 반대가 됩니다. 텍스트 조작을 위한 전용 도구를 사용하는 것이 더 좋습니다. 예를 들면 다음과 같습니다.

$ OUTPUT="$(cat /usr/src/linux/.config)"

$ time (echo $OUTPUT | OUTPUT="${OUTPUT//set/abc}")
real    0m1.766s
user    0m1.681s
sys     0m0.002s

$ time (echo $OUTPUT | sed s/set/abc/g >/dev/null)
real    0m0.094s
user    0m0.078s
sys     0m0.006s

답변4

가끔 셸에서 따옴표를 재사용하는 문제를 처리하고 싶다면 다음과 같이 할 수 있습니다.아니요삭제하는 것도 매우 간단합니다.

aq() { sh -c 'for a do
       alias "$((i=$i+1))=$a"
       done; alias' -- "$@"
}

함수 셸은 전달된 모든 인수 배열을 참조하고 반복 가능한 각 인수에 대한 출력을 증가시킵니다.

다음은 몇 가지 매개변수입니다.

aq \
"here's an
ugly one" \
"this one is \$PATHpretty bad, too" \
'this one```****```; totally sucks'

산출

1='here'"'"'s an
ugly one'
2='this one is $PATHpretty bad, too'
3='this one```****```; totally sucks'

이 출력 은 일반적으로 dash안전 따옴표로 묶인 작은따옴표 출력 에서 ​​나옵니다 '"'"'.bash'\''

$IFS및 를 사용하는 모든 POSIX 셸에서는 공백이 아니고 null이 아닌 선택된 단일 바이트를 다른 단일 바이트로 바꾸는 것이 아마도 가장 빠를 것입니다 $*.

set -f; IFS=\"\'\`; set -- $var; printf %s "$*"

산출

"some ""crazy """"""""string ""here

저는 단지 printf여러분이 볼 수 있도록 거기에 두는 것 뿐이지만, 물론 이렇게 하면 다음과 같습니다.

var="$*"

printf... 명령 대신 $var값은 출력에 표시되는 값이 됩니다.

내가 set -f쉘에게 지시할 때아니요to glob - 문자열에 glob 패턴으로 해석될 수 있는 문자가 포함된 경우. 쉘 파서가 glob 패턴을 확장하기 때문에 이렇게 합니다.뒤쪽에변수에 대해 필드 분할을 수행합니다. 와일드카드는 다음과 같이 다시 활성화할 수 있습니다 set +f. 일반적으로 스크립트에서 앞머리를 다음과 같이 설정하는 것이 유용하다고 생각합니다.

#!/usr/bin/sh -f

그럼명시적으로 와일드카드 활성화set +f내가 원하는 모든 라인 과 관련이 있습니다.

필드 분할은 의 문자를 기반으로 합니다 $IFS.

공백과 공백이 아닌 두 가지 $IFS값이 있습니다 . 공백$IFS$IFS$IFS(공백, 탭, 개행)생략된 것으로 지정된 필드 구분주문하다단일 필드로(또는 다른 것보다 앞에 있지 않으면 전혀 없음)- 그래서...

IFS=\ ; var='      '; printf '<%s>' $var
<>

그러나 다른 모든 항목은 단일 필드를 평가하도록 지정되었습니다.매번- 잘리지 않습니다.

IFS=/; var='/////'; printf '<%s>' $var
<><><><><>

모두기본적으로 변수 확장은 $IFS구분된 데이터 배열 입니다 $IFS. -quote로 인용하면 "배열 속성을 재정의하고 단일 문자열로 평가합니다.

그래서 내가 이 일을 할 때...

IFS=\"\'\`; set -- $var

셸의 인수 배열을 $IFS확장으로 생성된 구분된 필드 수로 설정했습니다. $var확장되면 포함된 문자의 구성 $IFS값 은 다음과 같습니다.잃어버린- 지금은 단지 필드 구분 기호일 뿐입니다. 입니다 \0NUL.

"$*"- 다른 큰따옴표 변수 확장과 마찬가지로 - 도 재정의됩니다 $IFS.또한, 첫 번째 바이트를 대체합니다.$IFS 구분된 각 필드에 대해존재하다 "$@". "그렇기 때문에첫 번째값은$IFS 이후의 모든 구분 기호 ""$*".분할할 때 "그 안에 포함될 필요도 없습니다. $IFS당신은 변경할 수 있습니다$IFS 뒤쪽에 set -- $args완전히 다른 값으로새로운그러면 첫 번째 바이트가 에서 필드 구분 기호로 나타납니다 "$*". 게다가 다음과 같이 모든 흔적을 완전히 제거할 수 있습니다:

set -- $var; IFS=; printf %s "$*"

산출

some crazy string here

관련 정보