변수에서 문자를 제거하는 방법에는 여러 가지가 있습니다.
지금까지 내가 찾은 가장 짧은 방법은 다음과 같습니다.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