3

I have to write a script, which will take all arguments and print them in reverse.

I've made a solution, but find it very bad. Do you have a smarter idea?

#!/bin/sh
> tekst.txt

for i in $* 
do
    echo $i | cat - tekst.txt > temp && mv temp tekst.txt
done

cat tekst.txt
1
  • You could add each to the front of a shell variable. Commented Sep 18, 2015 at 8:34

5 Answers 5

9

Could do this

for (( i=$#;i>0;i-- ));do
        echo "${!i}"
done

This uses the below
c style for loop
Parameter indirect expansion (${!i}towards the bottom of the page)

And $# which is the number of arguments to the script

Sign up to request clarification or add additional context in comments.

2 Comments

In ARITHMETIC EVALUATION i>0 is useless: u could: for((i=$#;i;i--)){ echo "${!i}";}
@F.Hauri It's not useless in arithmetic evaluation. In this particular case, sure you could use i on it's own, but only because 0 evaluates to false. Imagine you want every second param and there is an odd number. You will skip zero and cause a segfault
5

you can use this one liner:

echo $@ | tr ' ' '\n' | tac | tr '\n' ' '

2 Comments

Geat unless you have spaces in any of your arguments
will also break if you have glob characters in your arguments; will also break consecutive spaces; a better (and shorter and more efficient) method: printf '%s\n' "$@" | tac. Though, this will also break if you have newlines in your arguments.
2

bash:

#!/bin/bash
for i in "$@"; do
    echo "$i"
done | tac

call this script like:

./reverse 1 2 3 4

it will print:

4
3
2
1

2 Comments

Will break if arguments contain newlines. A shorter way is: printf '%s\n' "$@" | tac.
@gniourf_gniourf I finally have it: bash reverse function, without fork and without loop. The only eval use a limited predefined string.
1

Portably and POSIXly, without arrays and working with spaces and newlines:

Reverse the positional parameters:

flag=''; c=1; for a in "$@"; do set -- "$a" ${flag-"$@"}; unset flag; done

Print them:

printf '<%s>' "$@"; echo

1 Comment

local zCopy=; for a in "$@"; do set -- "$a" ${zCopy:+"$@"}; zCopy=t; done # Using :+ instead of - eliminates the possibility of being affected by or affecting a globally declared variable when used inside a function.
0

A loop is generally slow in bash, so I chose to use readarray to create a reversed array...

declare -a aReversed
readarray -d '' -t aReversed < <(printf '%s\0' "$@" | tac -s $'\0')

# aReversed now contains an array of arguments in reverse order

printf 'ARG %s\n' "${aReversed[@]}"

# or

for zArg in "${aReversed[@]}"; do
  printf 'ARG %s\n' "$zArg"
done

This handles newlines in arguments because...

  • readarray -d '' # tells readarray to split on null terminator (the space is needed)
  • readarray -t # tells readarray to exclude the terminator from the array values.
  • printf '\0' # tells printf to output a null byte.
  • tac -s '$\0' # tells tac that the file is null byte terminated.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.