You can get the number of operation down ever so slightly, and skip the call to seq:
for (( i = 1; i < ${#myarr[@]} - 1; ++i )); do
newarr+=( "${myarr[i]}" "${myarr[i]}" )
done
newarr=( "${myarr[0]}" "${newarr[@]}" "${myarr[-1]}" )
This assumes that newarr is empty to start with. Do unset newarry first if it's not.
As a function (this modifies the array that is passed):
dup_interal_items () {
typeset -n arr=$1
local tmparr
for (( i = 1; i < ${#arr[@]} - 1; ++i )); do
tmparr+=( "${arr[i]}" "${arr[i]}" )
done
arr=( "${arr[0]}" "${tmparr[@]}" "${arr[-1]}" )
}
The name of the array is passed into the function and the name-reference variable arr is used to access the elements in the array. At the end, the original array is updated to contain the result.
I did it this way rather than returning an array as you can only return an exit status from a function. The other approach would have been to pass both the names of an input array and an output array and use two name-reference variables in the function.
Or, you could possibly echo or printf the values in the function (in which case you don't have to construct a new array at all) and then parse that data in the main code. The function would then be required to be called inside a command substitution.
Note that you can't call this function with an array called arr due to the particular name scoping rules used by bash. You may want to rename the arr variable in the function if this is an issue.
Testing:
$ myarr=( 1 2 3 "here we go" )
$ dup_interal_items myarr
$ printf 'Element: %s\n' "${myarr[@]}"
Element: 1
Element: 2
Element: 2
Element: 3
Element: 3
Element: here we go
To duplicate all lines of a file except for the first and last line:
sed -e '1b' -e '$b' -e 'p' <file
The sed script branches to the end (where there is an implicit print statement) if it's on the first or last line, but prints all other lines (all other lines are therefore both explicitly printed by that last p and implicitly printed).
Or, as contributed by don_crissti,
sed 'p;1d;$d' <file
which explicitly prints each line, then ends the cycle for the first and last line, but prints all other lines implicitly (a second time).
An equivalent awk program that does not store more than a single line in memory would be non-trivial to write.
arrdeclared astypeset -n arr=$1inside the function body has global (script-wide) scope? (2) Among the three approaches when creating a bash function, which one do you suggest more or none? – Tim Nov 17 '18 at 21:08sedinstead of reading it and manipulating it. If the resulting data would go to a file, I would not read it into an array at all. – Kusalananda Nov 17 '18 at 21:13sedcommand that could do that for you. Why read it into an array inbash? – Kusalananda Nov 17 '18 at 22:41bash4.4.23's man page as I read: "The nameref attribute cannot be applied to array variables. "_ and that is precisely what you seem to be doing, since what you seem to pass to the function (as$1) is the array, not just its name by ref... and then applytypeset -n arr=$1. I am seriously confused.... o_O ... ¿?@! – Cbhihe Nov 18 '18 at 17:45namerefattribute. However,namerefvariables can reference array variables and subscripted array variables." In my code,arr(in the function) is not an array variable, it's an ordinary variable that I give thenamerefattribute to. It then references an array variable. – Kusalananda Nov 18 '18 at 17:55