How can I get sed to change all of the instances of each letter only once?

五迷三道 提交于 2019-12-01 12:14:54

问题


So far, the code only changes the first letter. If I take the break out, then it changes each instance of a letter more than once (which is bad). I'm simply attempting a caesar cipher using sed. I realize I could use tr to perform text transformations, but I'd prefer to stick with sed.

echo "What number do you want to use for the shift?"
read num

declare -A origin

x=({a..z})

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

for i in {0..25}
do
    origin[${x[i]}]=${y[i]}
done

for i in {0..25}
do
    origin[${x[i]}]=${y[i]}
done

for a in "${!origin[@]}"
do
    for x in "${!origin[@]}"
    do
        sed -i 's/'${x}'/'${origin[${x}]}'/g' test.txt
        break
    done
done

回答1:


The following performs a Caesar cipher (shift 3):

sed -i y/$(printf "%s" {a..z})/$(printf "%s" {d..z} {a..c})/ test.txt

Explanation

y is sed's translate command. $(printf "%s" {a..z}) returns a string of characters. To see how it all comes together, use echo. It shows the final sed command after bash has performed the expansions:

$ echo sed -i y/$(printf "%s" {a..z})/$(printf "%s" {d..z} {a..c})/ test.txt
sed -i y/abcdefghijklmnopqrstuvwxyz/defghijklmnopqrstuvwxyzabc/ test.txt

With this command, every occurrence of a will be replaced by d, every occurrence of b will be replaced e, and so on.

Variable Shift

The following script takes one argument, an integer. It then performs the Caesar shift for that integer:

#!/bin/bash
alpha=$( printf "%s" {a..z} )
part1=$( printf $(printf '\%03o' $(seq $((97+$1)) 122 ) ) )
part2=$( printf $(printf '\%03o' $(seq 97 $((97+$1-1)) ) ) )
sed -i y/$alpha/$part1$part2/ test.txt

For example, suppose we have this input file:

$ cat test.txt
and abc xyz 

Let's perform a 4-shift:

$ bash script.sh 4
$ cat test.txt
erh efg bcd



回答2:


This code does a Caesar Cypher on a test from the command line:

#!/usr/bin/env bash
declare -i n=$1
file=$2

alphabet="abcdefghijklmnopqrstuvwxyz"
key="${alphabet:n}${alphabet:0:n}"

sed -i -e "y/${alphabet}/${key}/" ${file}

You use it like this:

$ ./caesar.sh 4 test.txt



回答3:


#!/bin/bash

#This shit works:

echo "What number do you want to use for the shift?"
read num

declare -A origin

x=({a..z})

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

fromset=""
toset=""

for i in {0..25}
do
    fromset="$fromset${x[i]}"
    toset="$toset${y[i]}"
done

sed "y/$fromset/$toset/" original.txt > encoded.txt
sed "y/$toset/$fromset/" encoded.txt > decoded.txt


来源:https://stackoverflow.com/questions/29886943/how-can-i-get-sed-to-change-all-of-the-instances-of-each-letter-only-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!