How to do a circular shift of strings in bash?
Asked Answered
G

7

6

I have a homework assignment where I need to take input from a file and continuously remove the first word in a line and append it to the end of the line until all combinations have been done.

I really don't know where to begin and would be thankful for any sort of direction.

The part that has me confused is that this is suppose to be performed without the use of arrays. I'm not just fishing for someone to solve the problem for me, I'm just looking for some direction.

SAMPlE INPUT:

Pipes and Filters
Java Swing
Software Requirements Analysis

SAMPLE OUTPUT:

Analysis Software Requirements
Filters Pipes and
Java Swing
Pipes and Filters
Requirements Analysis Software
Software Requirements Analysis
Swing Java
Gracegraceful answered 5/4, 2010 at 12:23 Comment(1)
Similar: How do I split a string on a delimiter in Bash? at SORimola
T
6

A few tidbits that should help: when you call a function with a string, the string is split into multiple arguments (the positional parameters, named $n, where n are integers starting at 1) on the characters in the variable $IFS (which defaults to spaces, tabs and newlines)

function first() {
    echo $1
}
first one two three
# outputs: "one"

$* and $@ give you all the positional parameters, in order.

Second, the special variable $# holds the number of arguments to a function.

Third, shift discards the first positional parameter and moves up all the others by one.

function tail() {
    shift
    echo $*
}

Fourth, you can capture the output of commands and functions using `...` or $(...)

rest=`tail $*`

Fifth, you can send the output of one command to the input of another using the pipe character (|):

seq 5 | sort
Tenuis answered 5/4, 2010 at 12:34 Comment(4)
This was very helpful. I've figured out most of the assignment now and simply need to figure out how to store all of these strings in order to sort them alphabetically.Gracegraceful
Thanks a lot outis, I really appreciate the help. I like the simplicity of your tail() function.Gracegraceful
@Kyle: ghostdog74's (using prefix & suffix removal) are even simpler.Tenuis
@Kyle: note all the links are to the bash manual, also available at the command line by typing man bash. Familiarize yourself with it; it's a great resource for answering questions you have about bash.Tenuis
D
3

To get you started, check out the read builtin:

while read first_word rest_of_the_line; do
    ... your code here ...
done

You also need a way to feed your input file into that loop.

Drinkwater answered 5/4, 2010 at 12:27 Comment(0)
R
3

Let me allow to show you a quick working example based on @outis answer:

strings="string1 string2 string3"
next() { echo $1; }
rest() { shift; echo $*; }
for i in $strings; do
  echo $(next $strings)
  strings=$(rest $strings)
done

Or other way-round if you're interested in traversing by sequence:

strings="string1 string2 string3"
next() { echo $1; }
rest() { shift; echo $*; }
totalWords=$(c() { echo $#; }; c $strings)
for i in `seq -w 1 $totalWords`; do
  echo $i: $(next $strings)
  strings=$(rest $strings)
done
Rimola answered 8/5, 2015 at 18:5 Comment(1)
Like the simplicity of next() and rest() functions; +1Legion
A
0

this is short demo. Go through the words, get the last word and put in front of the string. until the final string is the same as the original.

    #!/bin/bash    
    s="Software Requirements Analysis"
    org="$s"
    while true
    do
       last=${s##* } #Analysis
       front=${s% *} #Software Requirements
       s="$last $front"
       echo $s
       case "$s" in
         "$org") break;;
       esac
    done

you should be able to do the rest using a file.

Amharic answered 5/4, 2010 at 13:3 Comment(3)
If I wanted it to remove the first word and append it to the end, what changes would I make to the following two lines? last=${s##* } #Analysis front=${s% } #Software Requirements I don't understand what the s## and s% * mean. Thank you very much for your answer, it is also very helpful.Gracegraceful
It isn't spacing my lines correctly in the comment, sorry for it being so messy.Gracegraceful
see here: en.tldp.org/LDP/abs/html/string-manipulation.html under substring removal for examples. you should be able to get a feel of how it works and do the necessary yourself.Amharic
N
0

Bash lets you address positional parameters using substring notation.

$ foo() { for ((i=1; i<=$#; i++)) { printf '%s ' "${@:$i}" "${@:1:$((i-1))}"; echo; }; }
$ foo one two three
one two three
two three one
three one two

Then, handling multiple lines of input is as simple as a while loop:

$ while read -a a; do foo "${a[@]}"; done < input.txt
Pipes and Filters
and Filters Pipes
Filters Pipes and
Java Swing
Swing Java
Software Requirements Analysis
Requirements Analysis Software
Analysis Software Requirements

Or if you're feeling adventurous, even:

$ while read; do foo $REPLY; done < input.txt

I don't see any explanation as to how your sample output is supposed to get in that order, so this solution ignores that aspect of your question.

Note that this doesn't handle all permutations/combinations, only the ones you specified in your question.

Natal answered 25/12, 2018 at 6:22 Comment(0)
M
0

Here is how you can circular left shift the chars in a string and how to circular left shift words on a line.

#!/bin/bash


# To left circular shift a string by chars
#
buf='12345'
bufsize=5

echo buf="$buf"
echo bufsize=$bufsize

for i in $(seq 10) c d e f; do
    buf=${buf:1:$bufsize}${buf:0:1}
    echo $buf
done

echo '--------------------------------------'
# to left circular shift a string by words
buf='one two three four "big bug"'
function lcs()
{
    s=$1
    shift
    echo $@ $s
}
for i in $(seq 10) c d e f; do
    buf=$(lcs $buf)
    echo $buf
done

output

$ ./test
buf=12345
bufsize=5
23451
34512
45123
51234
12345
23451
34512
45123
51234
12345
23451
34512
45123
51234
--------------------------------------
two three four "big bug" one
three four "big bug" one two
four "big bug" one two three
"big bug" one two three four
bug" one two three four "big
one two three four "big bug"
two three four "big bug" one
three four "big bug" one two
four "big bug" one two three
"big bug" one two three four
bug" one two three four "big
one two three four "big bug"
two three four "big bug" one
three four "big bug" one two
Milk answered 11/12, 2020 at 19:33 Comment(0)
S
-1

Parameter expansion will let you carve off parts of a variable.

Schist answered 5/4, 2010 at 12:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.