如何用变量控制Bash中tr命令的字符旋转次数?
tr Command in Bash Great question! Controlling the shift/rotation value for tr with a variable is totally achievable by generating the character mapping sets on the fly using Bash's string manipulation features. Let's break this down with practical examples:
Basic Implementation (Lowercase Letters Only)
Let's start with the core idea: tr works by mapping characters position-for-position between two sets. So we just need to generate the original character set (like a-z) and the shifted target set using our variable.
- First, define your rotation value (how many positions to shift right):
shift_amount=3
- Generate a string of consecutive lowercase letters to use as our base set:
lowercase_alphabet=$(printf "%s" {a..z})
This gives us the full string: abcdefghijklmnopqrstuvwxyz.
- Use Bash's substring slicing to create the shifted target set. We take the part of the alphabet starting at
shift_amount, then append the firstshift_amountcharacters to the end:
shifted_lowercase="${lowercase_alphabet:shift_amount}${lowercase_alphabet:0:shift_amount}"
For shift_amount=3, this becomes defghijklmnopqrstuvwxyzabc.
- Now pass both sets to
trto do the rotation:
echo "hello world" | tr "$lowercase_alphabet" "$shifted_lowercase"
Running this will output khoor zruog—perfect, that's a 3-position right shift!
Robustness Fix: Handle Shift Values Larger Than 26
If your shift value is bigger than 26 (like 30), it's equivalent to shifting 30 % 26 = 4 positions. Add a quick modulo operation to normalize the shift value first:
shift_amount=30 shift_amount=$((shift_amount % 26)) # Now shift_amount is 4 lowercase_alphabet=$(printf "%s" {a..z}) shifted_lowercase="${lowercase_alphabet:shift_amount}${lowercase_alphabet:0:shift_amount}" echo "hello" | tr "$lowercase_alphabet" "$shifted_lowercase" # Outputs "lipps"
Extend to Handle Both Lowercase and Uppercase
To rotate both cases at once, repeat the logic for uppercase letters:
shift_amount=2 lowercase_alphabet=$(printf "%s" {a..z}) uppercase_alphabet=$(printf "%s" {A..Z}) shifted_lowercase="${lowercase_alphabet:shift_amount}${lowercase_alphabet:0:shift_amount}" shifted_uppercase="${uppercase_alphabet:shift_amount}${uppercase_alphabet:0:shift_amount}" echo "Hello World!" | tr "$lowercase_alphabet$uppercase_alphabet" "$shifted_lowercase$shifted_uppercase"
This will output Jgnnq Yqtnf!—both cases shifted right by 2 positions.
Quick One-Liner (For Ad-Hoc Use)
If you want to skip defining separate variables for a quick command, you can condense this into a single line (though readability suffers a bit):
shift_amount=1; echo "hello" | tr "$(printf "%s" {a..z})" "$(printf "%s" {a..z} | sed "s/^.\{$shift_amount\}//;s/$/&$(printf "%s" {a..z} | cut -c1-$shift_amount)/")"
内容的提问来源于stack exchange,提问作者user9506231

