Bash:带有表示字符的变量的 tr 命令
Bash: tr command with variables representing chars
我想使用 tr 命令将字符映射到新字符,例如:
echo "hello" | tr '[a-z]' '[b-za-b]'
Will output: ifmmp
(小写字母表中的每个字母向右移动一个)
请参阅下面 '[b-za-b]'
的新字符映射:
[a b c d e f g h i j k l m n o p q r s t u v w x y z]
will map to:
[b c d e f g h i j k l m n o p q r s t u v w x y z a]
但是,当我想让它旋转多次时,如何使用变量来控制 tr 命令的旋转值?
例如:移位 1:
echo "hello" | tr '[a-z]' '[b-za-b]'
without variables and:
echo "hello" | tr '[a-z]' '[(a+$var)-za-(a+$var)]'
where $var=1
here I have: (a+$var)-z
representing the same as b-z
and
....................a-(a+$var)
representing the same as a-b
我曾尝试将 ascii 值转换为 char 以在 tr 命令中使用,但我认为这是不允许的。
我的问题是 bash 没有解释:
(a+$var)
作为字符 b
当 $var=1
(a+$var)
作为字符 c
当 $var=2
...等等
我如何告诉 bash 将这些等式解释为 tr 命令的字符
编辑
我尝试用数组来做,但它不起作用:
chars=( {a..z} )
var=2
echo "hello" | tr '[a-z]' '[(${chars[var]}-z)(a-${chars[var]})]'
我使用:(${chars[var]}-z)
表示 b-z
其中 var=1
因为 ${chars[1]}
是 b
但这不起作用。我错过了什么吗?
您可以使用八进制 \XXX
字符代码来实现您想要的字符。使用八进制代码,您可以对数字进行任何算术运算,然后将它们转换为字符代码
# rotr x
#
# if 0 <= x <= 25 rotr x outputs a set specification
# that could be used as an argument to tr command
# otherwise it outputs 'a-z'
function rotr(){
i = $(( 97 + ))
if [ $i -lt 97 ] ; then
translation='a-z'
elif [ $i -eq 97 ] ; then
translation='1-2' # 141 is the octal code for "a"
# 172 is the octal code for "z"
elif [ $i -eq 98 ] ; then
translation='2-21'
elif [ $i -lt 122 ] ; then # $i is between 99 and 121 ("c" and "y")
ii=$(echo "obase=8 ; $i" | bc)
jj=$(echo "obase=8 ; $(( $i - 1 ))" | bc)
translation=\$ii'-21-'\$jj
elif [ $i -eq 122 ] ; then
translation='21-1'
else # $i > 122
tranlation='a-z'
fi
echo $translation
}
现在您可以按如下方式使用它
echo hello | tr 'a-z' $(rotr 7)
打印
olssv
您尝试做的事情无法使用 tr
完成,而 不能 处理您的要求。此外,当您打算修改和使用变量以添加到 bash
中的 glob 模式时,这是您不可能做的事情。
你可以用 bash 数组做一个巧妙的小技巧!。 tr
命令也可以在普通的 glob 模式上采用扩展数组序列。首先定义一个源数组为
source=()
现在将其内容添加为 a-z
中的字符范围列表,使用大括号扩展 as
source=({a..z})
现在对于音译数组,从源数组,通过使用索引打印数组元素按如下方式构造它
trans=()
使用技巧从最后一个语法 ${array[@]: (-num)}
获取数组元素将得到总长度 - 元素数。所以首先构建数组为
var=2
trans+=( "${source[@]:(-(26-$var))}" )
现在构建数组的第二部分,使用另一个技巧 ${array[@]:0:num}
获得第一个 num
个元素。
trans+=( "${source[@]:0:$(( $var + 1 ))}" )
所以我们现在所做的是对于给定的 var=2
值,我们将 trans
数组构建为
echo "${trans[@]}"
c d e f g h i j k l m n o p q r s t u v w x y z a b c
现在您可以在 tr
命令中轻松使用它
echo "hello" | tr "${source[*]}" "${trans[*]}"
jgnnq
您可以将其全部放入函数中并将其值打印为
transChar() {
local source
local trans
local result
source=({a..z})
trans=()
var=""
input=""
trans+=( "${source[@]:(-(26-$var))}" )
trans+=( "${source[@]:0:$(( $var + 1 ))}" )
result=$( echo "$input" | tr "${source[*]}" "${trans[*]}" )
echo "$result"
}
一些测试
transChar "hello" 1
ifmmp
transChar "hello" 2
jgnnq
transChar "hello" 3
khoor
rot-random:
# generate alphabet as arr:
arr=( {1..26} )
i=$(($RANDOM%24+1))
# left and right
l=$(echo ${arr[$i]})
r=$(echo ${arr[$i+1]})
# reusing arr for testing:
echo ${arr[@]} | tr "a-z" "$r-za-$l"
echo "secret:" | tr "a-z" "$r-za-$l" ; echo $l $r $i
amkzmb:
h i 7
我想使用 tr 命令将字符映射到新字符,例如:
echo "hello" | tr '[a-z]' '[b-za-b]'
Will output:ifmmp
(小写字母表中的每个字母向右移动一个)
请参阅下面 '[b-za-b]'
的新字符映射:
[a b c d e f g h i j k l m n o p q r s t u v w x y z]
will map to:
[b c d e f g h i j k l m n o p q r s t u v w x y z a]
但是,当我想让它旋转多次时,如何使用变量来控制 tr 命令的旋转值?
例如:移位 1:
echo "hello" | tr '[a-z]' '[b-za-b]'
without variables and:
echo "hello" | tr '[a-z]' '[(a+$var)-za-(a+$var)]'
where $var=1here I have:
(a+$var)-z
representing the same asb-z
and....................
a-(a+$var)
representing the same asa-b
我曾尝试将 ascii 值转换为 char 以在 tr 命令中使用,但我认为这是不允许的。
我的问题是 bash 没有解释:
(a+$var)
作为字符 b
当 $var=1
(a+$var)
作为字符 c
当 $var=2
...等等
我如何告诉 bash 将这些等式解释为 tr 命令的字符
编辑
我尝试用数组来做,但它不起作用:
chars=( {a..z} )
var=2
echo "hello" | tr '[a-z]' '[(${chars[var]}-z)(a-${chars[var]})]'
我使用:(${chars[var]}-z)
表示 b-z
其中 var=1
因为 ${chars[1]}
是 b
但这不起作用。我错过了什么吗?
您可以使用八进制 \XXX
字符代码来实现您想要的字符。使用八进制代码,您可以对数字进行任何算术运算,然后将它们转换为字符代码
# rotr x
#
# if 0 <= x <= 25 rotr x outputs a set specification
# that could be used as an argument to tr command
# otherwise it outputs 'a-z'
function rotr(){
i = $(( 97 + ))
if [ $i -lt 97 ] ; then
translation='a-z'
elif [ $i -eq 97 ] ; then
translation='1-2' # 141 is the octal code for "a"
# 172 is the octal code for "z"
elif [ $i -eq 98 ] ; then
translation='2-21'
elif [ $i -lt 122 ] ; then # $i is between 99 and 121 ("c" and "y")
ii=$(echo "obase=8 ; $i" | bc)
jj=$(echo "obase=8 ; $(( $i - 1 ))" | bc)
translation=\$ii'-21-'\$jj
elif [ $i -eq 122 ] ; then
translation='21-1'
else # $i > 122
tranlation='a-z'
fi
echo $translation
}
现在您可以按如下方式使用它
echo hello | tr 'a-z' $(rotr 7)
打印
olssv
您尝试做的事情无法使用 tr
完成,而 不能 处理您的要求。此外,当您打算修改和使用变量以添加到 bash
中的 glob 模式时,这是您不可能做的事情。
你可以用 bash 数组做一个巧妙的小技巧!。 tr
命令也可以在普通的 glob 模式上采用扩展数组序列。首先定义一个源数组为
source=()
现在将其内容添加为 a-z
中的字符范围列表,使用大括号扩展 as
source=({a..z})
现在对于音译数组,从源数组,通过使用索引打印数组元素按如下方式构造它
trans=()
使用技巧从最后一个语法 ${array[@]: (-num)}
获取数组元素将得到总长度 - 元素数。所以首先构建数组为
var=2
trans+=( "${source[@]:(-(26-$var))}" )
现在构建数组的第二部分,使用另一个技巧 ${array[@]:0:num}
获得第一个 num
个元素。
trans+=( "${source[@]:0:$(( $var + 1 ))}" )
所以我们现在所做的是对于给定的 var=2
值,我们将 trans
数组构建为
echo "${trans[@]}"
c d e f g h i j k l m n o p q r s t u v w x y z a b c
现在您可以在 tr
命令中轻松使用它
echo "hello" | tr "${source[*]}" "${trans[*]}"
jgnnq
您可以将其全部放入函数中并将其值打印为
transChar() {
local source
local trans
local result
source=({a..z})
trans=()
var=""
input=""
trans+=( "${source[@]:(-(26-$var))}" )
trans+=( "${source[@]:0:$(( $var + 1 ))}" )
result=$( echo "$input" | tr "${source[*]}" "${trans[*]}" )
echo "$result"
}
一些测试
transChar "hello" 1
ifmmp
transChar "hello" 2
jgnnq
transChar "hello" 3
khoor
rot-random:
# generate alphabet as arr:
arr=( {1..26} )
i=$(($RANDOM%24+1))
# left and right
l=$(echo ${arr[$i]})
r=$(echo ${arr[$i+1]})
# reusing arr for testing:
echo ${arr[@]} | tr "a-z" "$r-za-$l"
echo "secret:" | tr "a-z" "$r-za-$l" ; echo $l $r $i
amkzmb:
h i 7