我有一个名为tmp.txt的文件。它在制表符分隔文件的一侧用空格分隔的字符“ a-z”和数字“ 0-9”。另一方面。对于每一行,我想随机替换1-3个字符。我的tmp.txt看起来像这样:
s h e h a d y o u r 0.9472 0.2074 0.4878 0.2227 0.4998 0.2841 0.5323 0.4254 0.539 0.4981
d o n t a s k m e t o c a r r y 0.9741 0.0999 0.338 0.0572 0.4514 0.223 0.5036 0.3835 0.4844 0.6306
e v e n t h e n 0.8549 0.1265 0.5248 0.2713 0.622 0.2011 0.4334 0.4137 0.4788 0.5435
到目前为止,我已经写了这么多脚本:
cat tmp.txt | while IFS= read -r line;
do
for i in {1..3};
do
a=$(tr -dc 'a-z0-9' | head -c $i);
b=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c $i);
sed -i 's/$a/$b/g';
done;
done
自从我得到之后,sed似乎并没有找到$ line。
sed: no input files
sed: no input files
sed: no input files
我以为我仍然在此循环的read -r行内,但看来我错了。有人知道我在做什么错吗?
预先感谢
答案 0 :(得分:2)
根本不使用sed
。特别是,不要为每行输入单独运行它三遍:命令替换很慢,而外部命令调用很慢甚至更慢。
#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*|4.0*) echo "ERROR: Bash 4.1+ required" >&2; exit 1;; esac
# Open a continuous stream of acceptable random characters
exec {random_chars_fd}< <(tr -dc 'a-z0-9' </dev/urandom)
while IFS= read -r line; do
for ((i=0; i<3; i++)); do
# filter for alpha and numeric characters in our input line
possible_chars=${line//[![:alnum:]]}
# pick a random position in the filtered string, and take the character it contains
char_to_replace=${possible_chars:$(( RANDOM % ${#possible_chars} )):1}
# now, read one character from our stream of random inputs
read -n 1 replacement <&$random_chars_fd
# and replace all instances of the randomly-selected character in our input with the
# randomly-selected output character.
line=${line//"$char_to_replace"/"$replacement"}
done
printf '%s\n' "$line" # print our new version of the line
done <tmp.txt
一些注释更改:
$(...)
或它们的旧反引号语法等效项)。旋转外部命令会导致大量开销,因此应尽可能使用内部bash操作代替;当我们 do 运行一个外部命令时,我们只运行一个副本并将其保留在整个脚本中,而不是一遍又一遍地启动新实例。cat
到循环中,而是重定向。如BashFAQ #24所述,这避免了严重的错误,并且效率更高。