변수에서 문자를 제거하는 방법에는 여러 가지가 있습니다.
지금까지 내가 알아낸 가장 짧은 방법은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
할것이다 '\''
.
공백이 아니고 null이 아닌 단일 바이트를 다른 단일 바이트로 바꾸는 것은 $IFS
및 를 사용하는 모든 POSIX 셸에서 가장 빠르게 수행될 수 있습니다 $*
.
set -f; IFS=\"\'\`; set -- $var; printf %s "$*"
산출
"some ""crazy """"""""string ""here
여기에서는 printf
여러분이 볼 수 있도록 작성했습니다. 물론, 제가 수행했다면 다음과 같습니다.
var="$*"
printf
... 명령 의 값 이 아니라 $var
출력에 표시되는 값이 됩니다.
set -f
내가 쉘에게 지시할 때~ 아니다to glob - 문자열에 glob 패턴으로 해석될 수 있는 문자가 포함된 경우. 쉘 파서가 글로브 패턴을 확장하기 때문에 이렇게 합니다.~ 후에변수에 대해 필드 분할을 수행합니다. globbing은 다음과 같이 다시 활성화할 수 있습니다 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
. 하나를 인용 하면 "
해당 배열 속성을 재정의하고 단일 문자열로 평가합니다.
그래서 내가 할 때 ...
IFS=\"\'\`; set -- $var
나는 셸의 인수 배열을 의 확장 으로 생성된 많은 $IFS
구분 필드 로 설정하고 있습니다. $var
확장되면 포함된 문자의 구성 값은 $IFS
다음과 같습니다.잃어버린- 지금은 필드 구분 기호일 뿐입니다. 입니다 \0NUL
.
"$*"
- 다른 큰따옴표로 묶인 변수 확장과 마찬가지로 - 의 필드 분할 특성도 무시합니다 $IFS
. 하지만,게다가, 첫 번째 바이트를 대체합니다.$IFS
구분된 각 필드에 대해안에 "$@"
. 그래서 "
그랬기 때문에첫 번째가치를 부여하다$IFS
모든 후속 구분 기호는 가 "
됩니다 "$*"
.그리고 분할할 때도 "
포함될 필요가 없습니다 . $IFS
당신은 변경할 수 있습니다$IFS
~ 후에 set -- $args
완전히 다른 값으로 변환하고새로운그러면 첫 번째 바이트가 의 필드 구분 기호로 표시됩니다 "$*"
. 또한 다음과 같이 모든 흔적을 완전히 제거할 수 있습니다.
set -- $var; IFS=; printf %s "$*"
산출
some crazy string here