3

I have managed to create two bash variables, both of which are lines of strings.

$oldfilenames which looks like

path/old-filename-1.txt
path/old-filename-2.txt
path/old-filename-3.txt
path/old-filename-4.txt
...

and

$newfilenames which looks like

new-filename-1.txt
new-filename-2.txt
new-filename-3.txt
new-filename-4.txt
...

and I would like to generate symbolic links in my directory using these two variables.

Both variables are of equal length. I am hoping to do something like this:

for x in $oldfilenames; y in $newfilenames; do 
  ln -s $x $y
done

I think that is not the correct syntax and I can't get it to work.

2 Answers2

2

I'm not sure that newline-delimited strings are a good way to handle sequences of filenames (you might want to look at using arrays instead).

However, given that's what you have, a combination of here strings with the read built-in's ability to read from numbered file descriptors might work:

while IFS= read -r -u3 x; IFS= read -r -u4 y; do 
  echo ln -s "$x" "$y"
done 3<<<"$oldfilenames" 4<<<"$newfilenames"

[the echo is included for testing purposes].

steeldriver
  • 81,074
  • That works! Thanks. I am also curious to know why my simple syntax above does not work and why this works. And what these fancy arrows are. – mindlessgreen Jun 09 '16 at 17:57
  • @rmf Your “simple syntax” is something you made up, it doesn't work because it isn't valid bash syntax. <<< is a here string, look it up in the bash manual. Regarding the number before it, see http://unix.stackexchange.com/questions/18899/when-would-you-use-an-additional-file-descriptor – Gilles 'SO- stop being evil' Jun 10 '16 at 00:29
2

There's no built-in construct to iterate over two lists at the same time. A for statement iterates over one list.

If you're using a shell with arrays, don't store lists as newline-delimited strings, use arrays instead.

If oldfilenames and newfilenames are arrays, you can iterate over the array index.

for ((i=0; i<${#oldfilenames[@]}; i++)); do
  x=${oldfilenames[$i]}; y=${newfilenames[$i]}; …
done

If you have to have newline-delimited strings, you can strip the first line, one line at a time.

nl='
'
oldfilenames=${oldfilenames%"$nl"}
while [ -n "$oldfilenames" ]; do
  x=${oldfilenames%%"$nl"*}; y=${newfilenames%%"$nl"*}
  oldfilenames=${oldfilenames#*"$nl"}; newfilenames=${newfilenames#*"$nl"};
  …
done