#!/bin/zsh
IFS=$'\n' # make newlines the only separator
set -f # disable globbing
zsh -f
, like csh -f
is to skip reading startup files, not to disable globbing (except when in sh/ksh emulation), for which you need set -o noglob
or set +o glob
(or variants with setopt
/unsetopt
).
You'd use set -f
in other Bourne-like shells to work around their misfeature by which globbing is performed upon unquoted expansions. But zsh doesn't have that misfeature as the globsubst
option is disabled by default (when not in sh
/ksh
emulation mode).
#show me the input from the command line
echo $1 ${#1}
It should be print -r -- $1 $#1
or echo -E - $1 $#1
or printf '%s\n' "$1 $#1"
or that won't work properly with values of $1
that contain \
s or some values that start with -
.
function randString() {
I'd choose between the randString() ...
Bourne syntax or function randString {
Korn syntax, but not use that combination (but then it's only a matter of taste).
# cat /dev/urandom | LC_ALL=C tr -cd "[a-z]" | head -c${#1}
Concat
enating a single file makes little sense.
Beware that with most tr
implementations, tr -cd "[a-z]"
would also produce [
and ]
characters.
$ echo '[]123ab' | tr -cd '[a-z]'
[]ab
$ echo '[]123ab' | tr -cd a-z
ab
}
for line in $(cat $1); do
That's not how you process text in shells. See Why is using a shell loop to process text considered bad practice?
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)/"
In there, the shell will perform the $(...)
expansions before calling sed
. randString \\1
calls randString
with a literal \1
as argument, so you end up calling sed
with a s/\([a-zA-Z0-9]\{2,\}\)@\([a-zA-Z0-9]\{2,\}\)\.\([a-zA-Z0-9]\{2,\}\)/\12@\22.\32/
argument.
Also beware that what [a-z]
and co. match depends on the locale.
Here, you should rather run one invocation of a text processing utility, preferably one that can generate random strings. Something like:
#! /bin/sh -
exec perl -Tpe 's{\w{2,}@\w{2,}\.\w{2,}}{
$& =~ s/\w/chr 96 + rand(26)/ger}ge' -- "$@"
Here using sh
instead of zsh
as sh
is more than enough and call perl
to do the text processing and generate random strings in a much much simpler and more efficient manner.
Or write a perl
script instead:
#! /usr/bin/perl --
while (<<>>) {
s{\w{2,}@\w{2,}.\w{2,}}{$& =~ s/\w/chr 96 + rand(26)/ger}ge;
print;
}
Here using <<>>
instead of <>
. The -p
option implies a <>
loop, which allows passing things like ls|
to process the output of ls
instead of the file called ls|
, but that's rather dangerous. Using the -T
option somewhat mitigates the security issues, <<>>
addresses it.
Doing something similar in zsh
internally is possible but would not be pretty.
#! /bin/zsh -
zmodload zsh/mathfunc
zmodload zsh/mapfile
set -o extendedglob
pattern='[:alnum:]@[:alnum:].[:alnum:]'
for file do
print -rn -- ${mapfile[$file]//(#m)$~pattern/${MATCH//(#m)[[:alnum:]]/${(L)$(( [##36] rand48() * 26 + 9))}}}
done
Here using:
$mapfile[file]
to load the contents of files
- zsh's own glob operators to do the matching instead of regexps
rand48()
to generate random numbers, here between 10 and 35 in base 36 to output letters A
to Z
, converted to lowercase with the L
parameter expansion flag.