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.
arr
declared astypeset -n arr=$1
inside 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:08sed
instead 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:13sed
command that could do that for you. Why read it into an array inbash
? – Kusalananda Nov 17 '18 at 22:41bash
4.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:45nameref
attribute. However,nameref
variables 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 thenameref
attribute to. It then references an array variable. – Kusalananda Nov 18 '18 at 17:55