bash commands to print file name and contents
We have a git repo with a ton of projects and each project has an OWNERS file with one line like 'teams/search' with no quotes. I would like to somehow find all those files and create an array of tuples where the tuple is [filename, filecontents].
I can find all files with
find java -name "OWNERS"
just fine or I can cat the contents like so
find java -name "OWNERS" | cat
How can I create the array though? The next step after that is looping over the array(I think I know how to do this though my bash is rusty) and I can create symlinks by cd to the team directory and ln -s {full file path}
bash data structures are not sophisticated enough to create an array of tuples. You can create an array of strings, or an associative array.
I'm assuming there are no newlines in the pathnames of the OWNERS files.
# an array of OWNERS filenames
mapfile -t owner_files < <(find java -name OWNERS)
# an associative array mapping the filename to the contents
declare -A owner_file_contents
for file in "${owner_files[@]}"; do
owner_file_contents["$file"]=$(<"file")
done
# inspect the associative array
declare -p owner_file_contents
Bash is very sensitive to filenames with spaces in the name, so you need to quote all the variables.
Some notes:
-
mapfile -t ary < <(some command)
-- runssome command
in a subshell and read the output into an array, one line per element.- This cannot be done with
some command | mapfile -t ary
because bash runs pipeline commands in separate subshells, which means the array would be created in a subshell, therefore the array will disappear when the subshell exits. - refs:
mapfile
command, 3.5.6 Process Substitution
- This cannot be done with
-
$(<file)
is a builtin way to do$(cat file)
without having to invoke an external command. Documented in 3.5.4 Command Substitution
Glenn's solution works great! I believe bash updated their data structures back in 2019? (The last I checked) to support mapfile..? It works great with arrays (and with tweaks works with maps as well).
Below is a sample pre-mapfile version that I put together quickly for dumping the content to the array.
array=( $(find find java -name "OWNERS") )
# loop over it
for i in ${array[@]}
do
file_val= "${i}"
file_contents="$(cat $i)"
echo $i: $file_contents
done