【问题标题】:Bash: tr command with variables representing charsBash:带有表示字符的变量的 tr 命令
【发布时间】:2018-03-17 06:12:01
【问题描述】:

我想使用 tr 命令将字符映射到新字符,例如:

echo "hello" | tr '[a-z]' '[b-za-b]' 将输出: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] 将映射到:

[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]' 没有变量和:

echo "hello" | tr '[a-z]' '[(a+$var)-za-(a+$var)]' 其中 $var=1

在这里我有:(a+$var)-z 代表与b-z 和

.......a-(a+$var) 表示与a-b相同

我尝试将 ascii 值转换为 char 以在 tr 命令中使用,但我认为这是不允许的。

我的问题是 bash 没有解释:

(a+$var) 作为字符 b 当 $var=1 时

(a+$var) 作为字符 c 当 $var=2 时

...等等

如何告诉 bash 将这些方程式解释为 tr 命令的字符

编辑

我尝试用一​​个数组来做,但它不起作用:

chars=( {a..z} )

var=2

回声“你好” | tr '[a-z]' '[(${chars[var]}-z)(a-${chars[var]})]'

我用:(${chars[var]}-z) 代表b-z where var=1

因为${chars[1]} 是b,但这不起作用。我错过了什么吗?

【问题讨论】:

标签: bash variables ascii tr


【解决方案1】:

您尝试做的事情无法使用tr 来完成,它不 能满足您的要求。此外,当您打算修改和使用变量以添加到 bash 中的 glob 模式时,这是您无法做到的。

你可以用 bash 数组做一个巧妙的小技巧! tr 命令也可以在普通 glob 模式上采用扩展数组序列。首先定义一个源数组为

source=()

现在使用大括号扩展将其内容添加为从a-z 开始的字符范围列表

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="$2"
    input="$1"
    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

【讨论】:

    【解决方案2】:

    随机旋转:

    # 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
    

    【讨论】:

      【解决方案3】:

      您可以使用八进制 \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 + $1 ))
         if [ $i -lt 97 ] ; then
              translation='a-z'
         elif [ $i -eq 97 ] ; then
              translation='\141-\172'  # 141 is the octal code for "a"
                                       # 172 is the octal code for "z" 
         elif [ $i -eq 98 ] ; then
              translation='\142-\172\141'
         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'-\172\141-'\\$jj
         elif [ $i -eq 122 ] ; then
              translation='\172\141-\171'
         else                              # $i > 122
              tranlation='a-z'
         fi
         echo $translation
      } 
      

      现在你可以按如下方式使用它

      echo hello | tr 'a-z' $(rotr 7)
      

      打印

      olssv
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-11-04
        • 1970-01-01
        • 2018-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多