1

I'm trying to recreate the script from this answer but without using read. I tried something like:

pids=()
for i in $(find /mnt/c/Projekte/test/pids/ -iname "*.pid")
do
    pids+=("$i")
done

declare -p $pids

But that only results in this:

./test.sh: line 9: declare: /mnt/c/Projekte/test/pids/a1.pid: not found

The test folder I created looks like this:

-rwxrwxrwx 1 vitus vitus   0 Mar  2 16:54 a1.pid
-rwxrwxrwx 1 vitus vitus   0 Mar  2 16:54 a2.pid
-rwxrwxrwx 1 vitus vitus   0 Mar  2 16:54 a3.pid
-rwxrwxrwx 1 vitus vitus  61 Mar  2 16:54 fill.sh
-rwxrwxrwx 1 vitus vitus 121 Mar  8 11:48 test.sh
Icoryx
  • 96
  • 7
  • What you are trying to do can't be made to work reliably. You need to use `read`, or do the processing within `find` by using the `-exec` option. If you run [Shellcheck](https://www.shellcheck.net/) on the code it reports the problem and provides links to explanations of what is wrong, and what to do about it. Also see [Bash Pitfalls #1 (for f in $(ls *.mp3))](https://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29) for excellent information about this. – pjh Mar 08 '22 at 12:03
  • 1
    Why do you not want to use `read`? – pjh Mar 08 '22 at 12:06
  • @pjh I'm trying to avoid `read` because the script should run automatically without requiring additional keyboard input and afaik `read` requires keyboard input? – Icoryx Mar 08 '22 at 15:13
  • `afaik read requires keyboard input?` No, read requires _input_, it could be input from keyboard, but it also can be input _from the output of `find`_. In shell `|` and `<` are some operators used for redirecting input. – KamilCuk Mar 08 '22 at 15:16
  • Ahh alright. Then I misunderstood the purpose of `read`. I encountered a different problem when trying the soltution from the post I linked in my question and thought that it was linked to `read` requiring keyboard input. – Icoryx Mar 08 '22 at 15:26
  • @Icoryx, as @KamilCuk has explained, `read` takes its input from standard input. It could be coming from a keyboard, a file, a pipe, a fifo, a socket, or various other sources. It looks from other comments that you are stuck with Bash 3. In that case the best code for you to use is the `while IFS= read -r -d '' a ...` code provided by @KamilCuk. It's rock solid. As always, run [Shellcheck](https://www.shellcheck.net/) on your finished code to ensure that no other common issues have slipped in. – pjh Mar 08 '22 at 17:43
  • The best resource for information about reading line-by-line in Bash is [BashFAQ/001 (How can I read a file \(data stream, variable\) line-by-line \(and/or field-by-field)?)](https://mywiki.wooledge.org/BashFAQ/001). One of the examples covers reading output from `find`. Most of the code that you will find in other places (including in accepted and/or extravagantly upvoted answers on Stackoverflow) doesn't work in general (or at all in some cases). – pjh Mar 08 '22 at 17:50

2 Answers2

1

To print a variable pass variable name.

declare -p pids

Using a loop on word-splitted result of a command to then properly quote it when adding to an array is odd. Just load it straight to an array.

 pids=($(find ....))

Note that you might want to set IFS=$'\n' before word splitting takes place, and you might want to research quoting and word splitting and filename expansion in shell.


Either way, you should do something along:

readarray -d '' -t pids < <(find /mnt/c/Projekte/test/pids/ -iname "*.pid" -print0)

or with while loop:

while IFS= read -r -d '' a; do
   pids+=("$a")
done < <(find /mnt/c/Projekte/test/pids/ -iname "*.pid" -print0)

See https://mywiki.wooledge.org/BashFAQ/001

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • I get an error from the line declare and it works without it. Excellent thank you –  Mar 08 '22 at 13:34
  • If I can just populate the array by doing `pids=($(find ....))` why does [this](https://stackoverflow.com/a/54561526/15051374) guy do it with `readarray` instead? I can't use `readarray` because I don't have bash 4.0. – Icoryx Mar 08 '22 at 15:18
  • `ou might want to research quoting and word splitting and filename expansion in shell.` because otherwise it undergoes word splitting and filename expansion. It will break on filenames with spaces and on filenames with `*`, for example. – KamilCuk Mar 08 '22 at 15:22
1

If you've got Bash 4.0 or later you can reliably populate the pids array without using find. Try this Shellcheck-clean code:

#! /bin/bash -p

shopt -s dotglob
shopt -s globstar
shopt -s nocaseglob
shopt -s nullglob

pids=( /mnt/c/Projekte/test/pids/**/*.pid )

declare -p pids
  • shopt -s dotglob enables globs to match files and directories that begin with .. find shows such files by default.
  • shopt -s globstar enables the use of ** to match paths recursively through directory trees.
  • shopt -s nocaseglob causes globs to match in a case-insensitive fashion (like find option -iname versus -name).
  • shopt -s nullglob makes globs expand to nothing when nothing matches (otherwise they expand to the glob pattern itself, which is almost never useful in programs).
  • The shopt commands can be combined into one if preferred: shopt -s dotglob globstar nocaseglob nullglob.
  • Note that this code might fail on versions of Bash prior to 4.3 because symlinks are (stupidly) followed while expanding ** patterns.
pjh
  • 6,388
  • 2
  • 16
  • 17
  • Unfortunately the system the script should run on does not have Bash 4.0 and cannot be updated atm :/ – Icoryx Mar 08 '22 at 15:09