This question already has answers here:
A variable modified inside a while loop is not remembered
(8 answers)
How can I store the "find" command results as an array in Bash
(8 answers)
Closed last year.
I have the following code which isn't working:
declare -a pids
find /foo/bar/ -iname "*.pid" -print0 | while read -d $'\0' file
do
pids+=("$file")
done
for i in "${pids[#]}"
do
echo $i
done
It should create an indexed array, search the given folder for all PIDs and append them to the array using a while loop however it seems that nothing is happening.
For me it looks like the results of find don't get appended to the array because the for loop at the bottom doesn't echo anything. I'm not sure if the += operant is correct for this but looking at similar question it seems to be. When trying to manually append a value to the array pids, instead of creating a new value on the next index it just adds the string to the first value (index 0).
For example this:
declare -a pids
pids+="foo1"
pids+="foo2"
results in this:
pids[0]="foo1foo2"
instead of:
pids[0]="foo1"
pids[1]="foo2"
Is += not the right operant for this or is something else wrong?
Related
This question already has answers here:
bash command not found when setting a variable
(2 answers)
Closed 2 years ago.
Bash in Linux give me command not found error in Line 9 where I do $array[$i]="Name_Of_File$i".
There are also the correct numbers printed besides the error. But i can't figure how it is possible. Maybe some spaces ? On the net i fuond these sintax of writing assignement with an array.
declare -a array;
start=0;
NumFile=$(ls -1 -d log/log_cassiere* | wc -l);
for (( i=$start; i<$NumFile; i++))
do
$array[$i]="Name_Of_File$i";
done
echo ${array[0]};
The problem with:
$array[$i]="Name_Of_File$i"
is that it is actually interpreting $array[$i] because you have a $ preceding it. That means it will attempt to replace the left side of the assignment with the value. Instead, you should have:
array[$i]="Name_Of_File$i"
This question already has answers here:
A variable modified inside a while loop is not remembered
(8 answers)
Closed 5 years ago.
I am writing a Bash Shell script, which reads a bunch of lines from a file, and tries to append each line to an array, thus:
# counter variable
i=0
cat doc.txt | while read -r line; do
myArr[i]="$line"
((i=i+1))
done
The file doc.txt contains one word in every line. When I print the array (through echo ${myArr[#]} or for x in ${myArr[#]};do echo $x; done), my array seems to be empty. What am I doing wrong? Thanks!
Edit: I also tried doing this in Ksh, with the same results. An answer in either Bash or Ksh is acceptable, since I seem to be having the same issue in both.
You are running the while loop in a subshell, so any changes you make to the array disappear once that shell exits. Use input redirection instead:
while IFS= read -r line; do
myArr+=("$line")
done < doc.txt
If you using bash 4.0 or later, you can use a single command
readArray -t myArr < doc.txt
This question already has answers here:
How do you store a list of directories into an array in Bash (and then print them out)?
(4 answers)
Closed 7 years ago.
I need to save content of two directories in an array to compare them later. Thats the solution i write:
DirContent()
{
#past '$1' directorys to 'directorys'
local DIRECTORYS=`ls -l --time-style="long-iso" $1 | egrep '^d' | awk '{print $8}'`
local CONTENT
local i
for DIR in $DIRECTORYS
do
i=+1
CONTENT[i]=${DIR}
done
echo $CONTENT
}
Then when I try to print this array I get empty output. Both directories are not empty. Please tell me what am I doing wrong here.
Thanks, Siery.
The core of this question is answered in the one I marked as a duplicate. Here are a few more pointers:
All uppercase variable names are discouraged as they are more likely to clash with environment variables.
You assign to DIRECTORYS (should probably be "directories") the output of a complicated command, which suffers from a few deficiencies:
Instead of backticks as in var=`command`, the syntax var=$(command) is preferred.
egrep is deprecated and grep -E is preferred.
The grep and awk commands could be combined to awk /^d/ '{ print $8 }'.
There are better ways to get directories, for example find, but the output of find shouldn't be parsed either.
You shouldn't process the output of ls programmatically: filenames can contain spaces, newlines, other special characters...
DIRECTORYS is now just one long string, and you rely on word splitting to iterate over it. Again, spaces in filenames will trip you up.
DIR isn't declared local.
To increase i, you'd use (( ++i )).
CONTENT[i]=${DIR} is actually okay: the i is automatically expanded here and doesn't have to be prepended by a $. Normally you'd want to quote your variables like "$dir", but in this case we happen to know that it won't be split any further as it already is the result of word splitting.
Array indices start at zero and you're skipping zero. You should increase the counter after the assignment.
Instead of using a counter, you can just append to an array with content+=("$dir").
To print the contents of an array, you'd use echo "${CONTENT[#]}".
But really, what you should do instead of all this: a call DirContent some_directory is equivalent to echo some_directory/*/, and if you want that in an array, you'd just use
arr=(some_directory/*/)
instead of the whole function – this even works for weird filenames. And is much, much shorter.
If you have hidden directories (names starts with .), you can use shopt -s dotglob to include them as well.
You can try
for((i=0;i<${#CONTENT[*]};i++))
do
echo ${CONTENT[$i]}
done
instead of echo $CONTENT
Also these change are required
((i=+1))
CONTENT[$i]=${DIR}
in your above code
This question already has answers here:
Capturing output of find . -print0 into a bash array
(13 answers)
Closed 7 years ago.
I would like to take the output of something that returns lines of elements possibly containing spaces to a bash array, with each line getting its own array element.
So for example:
find . -name \*.jpg
... may return a list of filenames. I want each filename to be assigned to an array. The simple solution doesn't work in general, because if there are spaces in filenames, the words get their own array element.
For example, start with this list of files in a directory:
FILE1.jpg
FILE2.jpg
FILE WITH SPACES.jpg
Try:
FILES=( $(find . -name \*.jpg) )
And you get (<> added for emphasis of individual elements):
$ for f in "${FILES[#]}"; do echo "<$f>"; done
<./FILE>
<WITH>
<SPACES.jpg>
<./FILE1.jpg>
<./FILE2.jpg>
This is not likely what you want.
How do you assign lines to array elements regardless of the lines containing spaces?
Set IFS before making the assignment. This allows bash to ignore the spaces by using only "\n" as the delimiter:
IFS=$'\n'
FILES=( $(find . -name \*.jpg) )
Now you get the result:
for f in "${FILES[#]}"; do echo "<$f>"; done
<./FILE WITH SPACES.jpg>
<./FILE1.jpg>
<./FILE2.jpg>
Note that how you access the array is important as well. This is covered in a similar question: BASH array with spaces in elements
I am trying to create multiple arrays holding random lists of file names referencing the number of elements in another array. How can I append a $cntr var (beginning with cntr=0) to the end of the new array names so they are directly referenced with elements in other array?
Wow I hope that reads somewhat sensible. Here is what I got going on so far that I hope helps make better sense of what I mean:
function fGenRanList() {
cntr=0
while [[ "$cntr" -lt "${#mTypeAr[#]}" ]] ; do
n="${nAr[$cntr]}" ; echo "\$n: $n"
tracks${cntr}=() ; echo "\$tracks${cntr}: $tracks${cntr}"
while ((n > 0)) && IFS= read -rd $'\0' ; do
tracks${cntr}+=("$REPLY")
((n--))
done < <(sort -zuR <(find "${dirAr[$cntr]}" -type f \( -name '*.mp3' -o -name '*.ogg' \) -print0))
((cntr++))
done
}
error I get is:
/home/user/bin/ranSong_multDirs.sh: line 95: syntax error near unexpected token `"$REPLY"'
/home/user/bin/ranSong_multDirs.sh: line 95: ` tracks${cntr}+=("$REPLY")'
But I first commentted out the echo statements from the tracks${cntr}=() array initialization to get rid of a similar error, but unsure whether or not track${cntr} gets initialized in the first place.
By the end I should end up with as many track(n) arrays as there are elements in ${#mTypeAr[#]}, using the numeric var stored in array ${nAr[$cntr]} to determine how many elements each track array will contain.
Maybe I am making things more difficult than need be, trying to implement arrays into older scripts I have both in order to make them a little more efficient, but I guess am driven primarily to get a better handle on using BASH arrays to store vars for similar but multiple processes which I seem to do often in my scripts.
Change this line, which is not valid bash syntax,
tracks${cntr}+=("$REPLY")
to
declare "tracks${cntr}+=($REPLY)"
Rather than having a syntactic assignment, the declare command takes a string that *look*s like an assignment as an argument; that argument is processed by the shell first, so if cntr is currently 3 and $REPLY is foo, the actual assignment performed is
tracks3+=(foo)
The declare command gives you a level of indirection in making parameter assignments.