如何通过 SED 适当地传递关联数组值?
How do I appropriately pass associated array values through SED?
我正在创建一个凯撒密码,如果字母表被颠倒,它会用匹配的字母替换单词中的字母。样本是 "abcdefghijklmnopqrstuvwxyz"。以下代码的输出生成 "abcdefghijklmmlkjihgfedcba"。所需的输出是反向的字母表,但是一旦编辑器到达中点,它就会反向返回而不是继续到最后。
declare -A origin
x=({a..z})
z=({z..a})
for i in {0..25}
do
origin[${x[i]}]=${z[i]}
done
for x in "${!origin[@]}"
do
sed -i 's/'${x}'/'${origin[${x}]}'/g' test.txt
done
你传递关联数组的方法是正确的,但是凯撒密码的逻辑是错误的。
因为对于 for
循环的每次迭代,sed
命令都会更改输入文件中的一些字符。该字符可以是输入文件中的原始字符,也可以是先前由较早的 sed 更改的字符。因此 for
循环实际上会进行多次转换而不是进行一次转换。
例如
考虑一个输入文件
$ cat test
a z
现在一个小的格式化脚本将是
for x in "${origin[@]}"; do sed -i "s/$x/${origin[$x]}/g" test; echo "$x ${origin[$x]}"; done;
z a
y b
x c
w d
v e
..
..
在第一次迭代中,sed
会将 z
更改为 a
。现在输入文件是
$cat test
a a
现在,在第 25 次迭代时,$x
将变为 a
,这会将输入中的 a
都转换为 z
$ cat test
z z
备选方案
可以使用 tr
作为
编写替代解决方案
$ a=$(echo {z..a} | tr -d " ")
$ b=$(echo {a..z} | tr -d " ")
$ echo {a..z} | tr $b $a
z y x w v u t s r q p o n m l k j i h g f e d c b a
为什么有效?
这里的字符是从输入中读取的,并用 tr
参数中的相应字符进行更改,这确保单个字符只更改一次。
不要忘记 bash 中的 字符索引 。在您的脚本中,不需要前 2 个 索引数组 x & y
。示例:
declare -A origin
x=abcdefghijklmnopqrstuvwxyz
z=zyxwvutsrqponmlkjihgfedcba
for i in {0..25}; do
origin[${x:i:1}]=${z:i:1}
done
没有什么比用 origin[{a..z}]
替换 {z..a}
并得到熟悉的结果更好的了?例如,仅查看 first 和 last 迭代。在 第一次迭代 中,您将所有 a
替换为 z
。然后在 最后一次迭代 中,您再次将所有 z
(包括您之前在第一次迭代中替换的 a->z
)替换为 a
' s 再次 -- 有效撤消您的更改。
一个更好的例子是看字母表的中点m->n
。
x=abcdefghijklmnopqrstuvwxyz
z=zyxwvutsrqponmlkjihgfedcba
||
当您的迭代达到 m
时,您将所有 m
替换为 n
。然后在下一次迭代中,将 n
替换为 m
。
你可以看到这看起来像是只有一半的替换受到影响。到达原点的中点后,任何替换只发生 一次,因为您不再遇到已经替换的字母。
使用之前发布的 tr
的解决方案看起来是您最好的选择之一。
我找到了解决问题的方法。谢谢两位的帮助!
#!/bin/bash
#Retrieve the desired shift from user
echo "What number do you want to use for the shift?"
read num
#Create an array of all letters
x=({a..z})
#Take user input and use to create the cipher array
case "$num" in
0)
y=({a..z})
;;
1)
y=({{b..z},a})
;;
2)
y=({{c..z},a,b})
;;
3)
y=({{d..z},a,b,c})
;;
4)
y=({{e..z},a,b,c,d})
;;
5)
y=({{f..z},{a..e}})
;;
6)
y=({{g..z},{a..f}})
;;
7)
y=({{h..z},{a..g}})
;;
8)
y=({{i..z},{a..h}})
;;
9)
y=({{j..z},{a..i}})
;;
10)
y=({{k..z},{a..j}})
;;
11)
y=({{l..z},{a..k}})
;;
12)
y=({{m..z},{a..l}})
;;
13)
y=({{n..z},{a..m}})
;;
14)
y=({{o..z},{a..n}})
;;
15)
y=({{p..z},{a..o}})
;;
16)
y=({{q..z},{a..p}})
;;
17)
y=({{r..z},{a..q}})
;;
18)
y=({{s..z},{a..r}})
;;
19)
y=({{t..z},{a..s}})
;;
20)
y=({{u..z},{a..t}})
;;
21)
y=({{v..z},{a..u}})
;;
22)
y=({{w..z},{a..v}})
;;
23)
y=({{x..z},{a..w}})
;;
24)
y=({{y..z},{a..x}})
;;
25)
y=({{z..z},{a..y}})
;;
*)
echo "Sorry, you must use a shift from 0 to 25."
;;
esac
#create the string variables for manipulation
fromset=""
toset=""
#place the alphabetic arrays into the atring variables
for i in {0..25}
do
fromset="$fromset${x[i]}"
toset="$toset${y[i]}"
done
#Use sed text transformations to alter given files
sed "y/$fromset/$toset/" original.txt > encoded.txt
sed "y/$toset/$fromset/" encoded.txt > decoded.txt
我正在创建一个凯撒密码,如果字母表被颠倒,它会用匹配的字母替换单词中的字母。样本是 "abcdefghijklmnopqrstuvwxyz"。以下代码的输出生成 "abcdefghijklmmlkjihgfedcba"。所需的输出是反向的字母表,但是一旦编辑器到达中点,它就会反向返回而不是继续到最后。
declare -A origin
x=({a..z})
z=({z..a})
for i in {0..25}
do
origin[${x[i]}]=${z[i]}
done
for x in "${!origin[@]}"
do
sed -i 's/'${x}'/'${origin[${x}]}'/g' test.txt
done
你传递关联数组的方法是正确的,但是凯撒密码的逻辑是错误的。
因为对于 for
循环的每次迭代,sed
命令都会更改输入文件中的一些字符。该字符可以是输入文件中的原始字符,也可以是先前由较早的 sed 更改的字符。因此 for
循环实际上会进行多次转换而不是进行一次转换。
例如
考虑一个输入文件
$ cat test
a z
现在一个小的格式化脚本将是
for x in "${origin[@]}"; do sed -i "s/$x/${origin[$x]}/g" test; echo "$x ${origin[$x]}"; done;
z a
y b
x c
w d
v e
..
..
在第一次迭代中,sed
会将 z
更改为 a
。现在输入文件是
$cat test
a a
现在,在第 25 次迭代时,$x
将变为 a
,这会将输入中的 a
都转换为 z
$ cat test
z z
备选方案
可以使用 tr
作为
$ a=$(echo {z..a} | tr -d " ")
$ b=$(echo {a..z} | tr -d " ")
$ echo {a..z} | tr $b $a
z y x w v u t s r q p o n m l k j i h g f e d c b a
为什么有效?
这里的字符是从输入中读取的,并用 tr
参数中的相应字符进行更改,这确保单个字符只更改一次。
不要忘记 bash 中的 字符索引 。在您的脚本中,不需要前 2 个 索引数组 x & y
。示例:
declare -A origin
x=abcdefghijklmnopqrstuvwxyz
z=zyxwvutsrqponmlkjihgfedcba
for i in {0..25}; do
origin[${x:i:1}]=${z:i:1}
done
没有什么比用 origin[{a..z}]
替换 {z..a}
并得到熟悉的结果更好的了?例如,仅查看 first 和 last 迭代。在 第一次迭代 中,您将所有 a
替换为 z
。然后在 最后一次迭代 中,您再次将所有 z
(包括您之前在第一次迭代中替换的 a->z
)替换为 a
' s 再次 -- 有效撤消您的更改。
一个更好的例子是看字母表的中点m->n
。
x=abcdefghijklmnopqrstuvwxyz
z=zyxwvutsrqponmlkjihgfedcba
||
当您的迭代达到 m
时,您将所有 m
替换为 n
。然后在下一次迭代中,将 n
替换为 m
。
你可以看到这看起来像是只有一半的替换受到影响。到达原点的中点后,任何替换只发生 一次,因为您不再遇到已经替换的字母。
使用之前发布的 tr
的解决方案看起来是您最好的选择之一。
我找到了解决问题的方法。谢谢两位的帮助!
#!/bin/bash
#Retrieve the desired shift from user
echo "What number do you want to use for the shift?"
read num
#Create an array of all letters
x=({a..z})
#Take user input and use to create the cipher array
case "$num" in
0)
y=({a..z})
;;
1)
y=({{b..z},a})
;;
2)
y=({{c..z},a,b})
;;
3)
y=({{d..z},a,b,c})
;;
4)
y=({{e..z},a,b,c,d})
;;
5)
y=({{f..z},{a..e}})
;;
6)
y=({{g..z},{a..f}})
;;
7)
y=({{h..z},{a..g}})
;;
8)
y=({{i..z},{a..h}})
;;
9)
y=({{j..z},{a..i}})
;;
10)
y=({{k..z},{a..j}})
;;
11)
y=({{l..z},{a..k}})
;;
12)
y=({{m..z},{a..l}})
;;
13)
y=({{n..z},{a..m}})
;;
14)
y=({{o..z},{a..n}})
;;
15)
y=({{p..z},{a..o}})
;;
16)
y=({{q..z},{a..p}})
;;
17)
y=({{r..z},{a..q}})
;;
18)
y=({{s..z},{a..r}})
;;
19)
y=({{t..z},{a..s}})
;;
20)
y=({{u..z},{a..t}})
;;
21)
y=({{v..z},{a..u}})
;;
22)
y=({{w..z},{a..v}})
;;
23)
y=({{x..z},{a..w}})
;;
24)
y=({{y..z},{a..x}})
;;
25)
y=({{z..z},{a..y}})
;;
*)
echo "Sorry, you must use a shift from 0 to 25."
;;
esac
#create the string variables for manipulation
fromset=""
toset=""
#place the alphabetic arrays into the atring variables
for i in {0..25}
do
fromset="$fromset${x[i]}"
toset="$toset${y[i]}"
done
#Use sed text transformations to alter given files
sed "y/$fromset/$toset/" original.txt > encoded.txt
sed "y/$toset/$fromset/" encoded.txt > decoded.txt