입력과 동일한 길이의 임의 문자열을 생성하여 고정 길이 텍스트 파일의 이메일 주소를 표시하려고 합니다. sed에서 문자열을 역참조로 전달하고 있습니다.
단순화하기 위해 이 스크립트(임시)는 다음과 같습니다.
#!/bin/zsh
IFS=$'\n' # make newlines the only separator
set -f # disable globbing
#show me the input from the command line
echo $1 ${#1}
function randString() {
# just echo for demonstration
echo $1 ${#1}
# this is the bit I really want:
# cat /dev/urandom | LC_ALL=C tr -cd "[a-z]" | head -c${#1}
}
for line in $(cat $1); do
echo $line |
sed "s/\([a-zA-Z0-9]\{2,\}\)@\([a-zA-Z0-9]\{2,\}\)\.\([a-zA-Z0-9]\{2,\}\)/$(randString \\1)@$(randString \\2).$(randString \\3)/"
done
다음 데이터(temp.txt)를 사용하십시오.
me [email protected]
you [email protected]
다음과 같이 실행하세요:
./temp temp.txt
나에게 다음과 같은 출력을 제공합니다.
temp.txt 8
me myemail 2@someserver 2.com 2
you youremail 2@anotherserver 2.biz 2
문제는 ${#1}
어떤 문자열을 입력해도 2가 반환된다는 것입니다. 길이 $1
가 잘못된 올바른 문자열을 어떻게 반환할 수 있습니까 ${#1}
? IFS
파일 반복 설정으로 인해 기능이 종료됩니까?
참고: 저는 Mac을 사용하고 있으므로 GNU 확장이 없습니다.
답변1
일부 진단 비트는 무슨 일이 일어나고 있는지 보여줍니다.
이 줄을 함수 echo rand $1 ${#1} >&2
에 추가하면 출력은 다음과 같습니다.randString
temp.txt 8
rand \1 2
rand \2 2
rand \3 2
me myemail 2@someserver 2.com 2
rand \1 2
rand \2 2
rand \3 2
you youremail 2@anotherserver 2.biz 2
stderr
입력을 with 로 에코함으로써 역참조가 표시해야 하는 문자열 대신 인수 , 및 (길이 2)를 사용 하여 호출되고 있음 >&2
을 알 수 있습니다 .randString
\1
\2
\3
다음 테스트는 호출 앞에 sed
with를 추가하여 echo
어떤 인수를 받는지 확인하는 것입니다. 출력:
sed s/\([a-zA-Z0-9]\{2,\}\)@\([a-zA-Z0-9]\{2,\}\)\.\([a-zA-Z0-9]\{2,\}\)/\1 2@\2 2.\3 2/
이런 식으로 sed
문자열을 \1 2
입력 문자열에 대한 역참조인 that과 같은 것으로 바꾸고 그 뒤에 공백과 숫자 2를 입력하라는 메시지가 표시됩니다. 입력 이메일 주소의 문자열은 함수 sed
가 아닌 에서 옵니다.echo
이는 문자열이 인수로 전달되기 전에 $(...)
문자열의 명령 대체(확장)가 처리되기 때문입니다 . 입력 문자열을 함수에 전달하려면 쉘 함수를 호출해야 합니다. 하지만 아마도 이렇게 할 방법은 없을 것입니다zsh
sed
sed
기본 버전sed
.
추가하도록 편집됨: 기본적으로 이메일 주소 수정을 위한 빠른 스크립트 zsh
:
#!/usr/bin/env zsh
setopt extendedglob
coproc cat /dev/urandom | LC_ALL=C tr -cd "[:lower:]"
getRand (){
print -r -- ${1//(#m)[[:alnum:]]/$(read -psk var;echo $var)}
}
while read line; do
print -r -- ${line/(#m)[[:alnum:]](#c2,)@[[:alnum:]](#c2,).[[:alnum:]](#c2,)/$(getRand ${MATCH})}
done < ${1:?}
답변2
#!/bin/zsh IFS=$'\n' # make newlines the only separator set -f # disable globbing
zsh -f
이는 csh -f
와일드카드를 비활성화하는 대신(sh/ksh 에뮬레이션 제외) set -o noglob
또는 set +o glob
(또는 setopt
/ 를 사용한 변형 unsetopt
) 읽기를 건너뛰는 것과 같습니다.
set -f
인용되지 않은 확장에서 와일드카드를 수행하는 버그가 있는 기능을 해결하기 위해 다른 Bourne과 같은 쉘에서 이것을 사용할 수 있습니다 . 하지만 zsh globsubst
에는 이 옵션이 기본적으로 비활성화되어 있으므로( sh
/ ksh
에뮬레이션 모드가 아닌 경우) 이러한 결함이 없습니다 .
#show me the input from the command line echo $1 ${#1}
print -r -- $1 $#1
또는 또는 또는 이어야 하며 , echo -E - $1 $#1
s가 포함된 값이나 로 시작하는 일부 값에 대해서는 printf '%s\n' "$1 $#1"
제대로 작동하지 않습니다 .$1
\
-
function randString() {
나는 randString() ...
Bourne 구문이나 Korn 구문 function randString {
중 하나를 선택 하지만 그 조합은 선택하지 않습니다(그러나 그것은 단지 취향의 문제입니다).
# cat /dev/urandom | LC_ALL=C tr -cd "[a-z]" | head -c${#1}
개별 파일을 연결하는 데는 cat
거의 의미가 없습니다 .
대부분의 tr
구현 에서는 및 문자 tr -cd "[a-z]"
도 생성됩니다 .[
]
$ echo '[]123ab' | tr -cd '[a-z]'
[]ab
$ echo '[]123ab' | tr -cd a-z
ab
} for line in $(cat $1); do
이는 쉘에서 텍스트가 처리되는 방식이 아닙니다. 바라보다쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?
echo $line | sed "s/\([a-zA-Z0-9]\{2,\}\)@\([a-zA-Z0-9]\{2,\}\)\.\([a-zA-Z0-9]\{2,\}\)/$(randString \\1)@$(randString \\2).$(randString \\3)/"
거기에서 쉘은 $(...)
그것을 호출하기 전에 확장을 수행 합니다 sed
. 리터럴을 인수로 사용 하여 호출이 이루어 randString \\1
지므로 결국 인수를 사용하여 호출됩니다.randString
\1
sed
s/\([a-zA-Z0-9]\{2,\}\)@\([a-zA-Z0-9]\{2,\}\)\.\([a-zA-Z0-9]\{2,\}\)/\12@\22.\32/
또한 무엇 [a-z]
과 공동을 기록하십시오. 일치는 로케일에 따라 다릅니다.
여기서는 텍스트 처리 유틸리티(무작위 문자열을 생성할 수 있는 유틸리티)에 대한 호출을 실행해야 합니다. 그것은 다음과 같습니다:
#! /bin/sh -
exec perl -Tpe 's{\w{2,}@\w{2,}\.\w{2,}}{
$& =~ s/\w/chr 96 + rand(26)/ger}ge' -- "$@"
여기에서는 as sh
대신 사용하는 것으로 충분하며 텍스트 처리를 수행하고 임의 문자열을 생성하는 더 간단하고 효율적인 방법이 필요합니다.zsh
sh
perl
아니면 perl
대신 스크립트를 작성하세요:
#! /usr/bin/perl --
while (<<>>) {
s{\w{2,}@\w{2,}\.\w{2,}}{$& =~ s/\w/chr 96 + rand(26)/ger}ge;
print;
}
여기서는 <<>>
대신 사용되었습니다 <>
. 해당 옵션은 이름이 지정된 파일이 아닌 프로세스의 출력과 같은 항목을 전달할 수 있는 루프를 -p
의미합니다 .<>
ls|
ls
ls|
꽤 위험하다. 이 옵션을 사용하면 -T
보안 문제를 어느 정도 완화하고 해결할 수 있습니다.<<>>
내부적으로 비슷한 작업을 수행하는 zsh
것이 가능 하지만 예쁘지는 않습니다.
#! /bin/zsh -
zmodload zsh/mathfunc
zmodload zsh/mapfile
set -o extendedglob
pattern='[[:alnum:]](#c2,)@[[:alnum:]](#c2,).[[:alnum:]](#c2,)'
for file do
print -rn -- ${mapfile[$file]//(#m)$~pattern/${MATCH//(#m)[[:alnum:]]/${(L)$(( [##36] rand48() * 26 + 9))}}}
done
여기에 사용됨:
$mapfile[file]
파일의 내용을 로드합니다.- zsh의 자체 glob 연산자는 일치를 위해 정규식을 대체합니다.
rand48()
여기에서는 10에서 35 사이의 36진수로 난수를 생성하고 문자를A
에 출력Z
하고 매개변수 확장 플래그를 사용하여 소문자로 변환합니다L
.