Reputation: 67
I am very new to shell script and trying my best to get hands on this language. I am trying to assign each line available in a text file to an array
For example, I have a text file as below.
I want to assign each line to an array as below.
Expected Output:
Array[0]="delectus aut autem"
Array[1]="quis ut nam facilis et officia qui"
Array[2]="fugiat veniam minus"
But, on executing the below code, We are observing that each element in array is assigned based on the space in each line
Shell Script:
#!/bin/sh
cmd=$(curl https://jsonplaceholder.typicode.com/todos)
echo $cmd > Data.json
echo $(jq '.[] | .title' Data.json) > title.txt
echo "text file creation done!"
filename=title.txt
declare -a myArray
myArray=(`cat "$filename"`)
printf '%s\n' "${myArray[@]}"
for (( i = 0 ; i < 20 ; i++))
do
echo "Element [$i]: ${myArray[$i]}"
done
Current Output:
Can someone throw some light on this?
Upvotes: 2
Views: 45
Reputation: 601
What you can try to use a while loop to read each line into an array
#!/bin/sh
cmd=$(curl -s https://jsonplaceholder.typicode.com/todos)
echo "$cmd" > Data.json
jq -r '.[] | .title' Data.json > title.txt
myArray=()
# Read each line
while IFS= read -r line; do
myArray+=("$line")
done < title.txt
for (( i = 0 ; i < 20 ; i++ )); do
echo "Array[$i]=\"${myArray[$i]}\""
done
Upvotes: 0
Reputation: 84609
Your biggest issue is using the POSIX shell interpreter line #!/bin/sh
. POSIX shell does not support arrays. You need to use an advanced shell like bash
, which provides for both indexed, declare -a
arrays and associative, declare -A
arrays. Given you use declare -a
it appears you mean to use bash
. So change the interpreter line to #!/bin/bash
and you will have arrays available.
You are further in luck, bash
provides mapfile
(synonymous with readarray
) builtin commands that will read a file, line-by-line, into elements of an indexed array. You can use either mapfile
or readarray
, they are the same command, just aliases for each other.
When you want to loop over the array, use the parameter expansion ${#myArray[@]}
to return the number of elements in the array rather then hardcoding 20
or some other number.
Don't use cat ...
unnecessarily to pipe information around. That is called a UUOc (Unnecessary Use of cat
, also stated as Useless Use of cat
). See Useless Use of Cat. Instead use >
and <
to redirect to/from files.
Always paste your script into ShellCheck to find any issue (good idea before posting here too)
Putting it altogether, you could modify your script as follows. This isn't the only way to do it, but a reasonable one:
#!/bin/bash
## assign filenames from 1st two command-line arguments
# use Data.json and title.txt by default if no arguments given
websrc="${1:-Data.json}"
txtfile="${2:-title.txt}"
## use redirection to save the curl data to Data.json
curl https://jsonplaceholder.typicode.com/todos > "$websrc"
## use redirection to save jq output to title.txt
jq '.[] | .title' "$websrc" > "$txtfile"
## optional output, but make information useful
# check "%txtfile" exists and is non-empty
if [ -s "$txtfile" ]; then
printf "text file creation done!\n"
else # otherwise handle the error and exit with error code 1
printf "error: failed to create txtfile '%s'\n" "$txtfile" >&2
exit 1
fi
## declare indexed array
declare -a myArray
## read the $txtfile into array
mapfile -t myArray < "$txtfile"
## no need to duplicate output
# printf '%s\n' "${myArray[@]}"
## use array to determine number of elements (200 in test)
for (( i = 0 ; i < ${#myArray[@]}; i++))
do
printf "Element [%d]: %s\n" "$i" "${myArray[$i]}"
done
Note: See Why is printf better than echo? to understand why I changed your echo ...
use to printf ...
Example Use/Output
Since you provided the URL, the output of the script is:
$ bash curl-json-mapfile.sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 24311 0 24311 0 0 136k 0 --:--:-- --:--:-- --:--:-- 137k
text file creation done!
Element [0]: "delectus aut autem"
Element [1]: "quis ut nam facilis et officia qui"
Element [2]: "fugiat veniam minus"
Element [3]: "et porro tempora"
Element [4]: "laboriosam mollitia et enim quasi adipisci quia provident illum"
Element [5]: "qui ullam ratione quibusdam voluptatem quia omnis"
Element [6]: "illo expedita consequatur quia in"
Element [7]: "quo adipisci enim quam ut ab"
Element [8]: "molestiae perspiciatis ipsa"
Element [9]: "illo est ratione doloremque quia maiores aut"
Element [10]: "vero rerum temporibus dolor"
...
Element [195]: "consequuntur aut ut fugit similique"
Element [196]: "dignissimos quo nobis earum saepe"
Element [197]: "quis eius est sint explicabo"
Element [198]: "numquam repellendus a magnam"
Element [199]: "ipsam aperiam voluptates qui"
All 200 elements successfully stored in the array, and much easier than looping with read -r
(which is another valid option)
Look things over and let me know if you have questions.
Upvotes: 1