0

I have searched for variable syntax and other commands but I cannot get through.

I have some folders created with btrfs snapshots. Within each folder there is a file called /etc/fstab that I need to edit and replace always the same value with the one from the folder's path. For example I replace @ with @snapshots/daily/root2020-12-27_19H05

The variable here is 2020-12-27_19H05 always prefixed with root.

Before I get to editing a file, 1st step is to do something simple like making a simple bash script which creates a file as root in each folder found by the variable, I have:

cd /.snapshots/daily
SNAPSHOTS=$(ls -d root*/)
echo > $SNAPSHOTS/test

But I get the following error:

bash: $SNAPSHOTS/test: ambiguous redirect

I tried various ways with "", '', (), {} in every location I could think of but it fails. I tried with SUDO in some places but fails as well. It seems common on internet but what I read didn't me understand and fix my issue.

What am I doing wrong?

Thanks!

Frank
  • 1
  • Hi, welcome to Unix Stackexchange! Your description for the problem is very clear, but I find your title a bit hard to understand for the first reading. That doesn't encourage other users to click the title and see inside what your post actually says, and it's also bad for search engine optimization. Maybe you could reconsider the title phrasing? – 把友情留在无盐 Dec 29 '20 at 03:10
  • You're right, I changed it, trying to keep it short but also meaningful. – Frank Dec 29 '20 at 03:17

3 Answers3

0

Your SNAPSHOTS variable contains spaces. To redirect to its value, double quote it:

echo > "$SNAPSHOTS"/test

This will most likely not do what you want as you seems to want to store multiple path in SNAPSHOTS. You can't store multiple separate strings in one string and think you can retrieve them back out of that single string correctly. It should really be an array and you don't need ls at all here:

shopt -s nullglob

SNAPSHOTS=(root*/)

for snap in "${SNAPSHOTS[@]}"; do echo >"$snap"/test done

or just

shopt -s nullglob

for snap in root*/; do echo >"$snap"/test done

Setting the nullglob shell option ensures that the pattern is removed completely if it doesn't match anything. Without nullglob, the pattern is retained as is if it doesn't match anything.

If it's not many thousands of files that you want to put an empty line into, you could also do

shopt -s nullglob

SNAPSHOTS=(root*/) echo | tee "${SNAPSHOTS[@]/%//test}" >/dev/null

If you really just want to create the files (not write an empty line into them), then use touch:

shopt -s nullglob

SNAPSHOTS=(root*/) touch "${SNAPSHOTS[@]/%//test}" 2>/dev/null

Kusalananda
  • 333,661
0

Probably SNAPSHOTS contains more than one directory.

You can see the problem when you insert a line set -x before the echo command. This will show the expansion of $SNAPSHOTS.

Use a loop to call the echo command for every matching directory.

for i in root*/
do
    if [ "$i" != 'root*/' ]
    then
        touch "$i"/test
    fi
done

The additional if avoids running touch 'root*/test' in case there is no matching directory.

Bodo
  • 6,068
  • 17
  • 27
0

You guys know everything and explain the answer so we can understand, this website is an incredible database.

In the end I went with

for i in root*/
do
    if [ "$i" != 'root*/' ]
    then
        sudo touch "$i"/test
    fi
done

Using sudo here cuz those snapshot folders are owned by root.

So now I understand my first step which is to create, rename, delete, change permissions, etc. on a file within a list of folders returned inside a variable.

I am now bringing this a step deeper, which is to edit a file within each of the folders returned by the variable, and replace a fixed value by a variable one which equals the value returned by the variable at the start.

I can't understand how to integrate a variable in the value I want to replace.

I changed my snapshots structure to make the script easier (for me). So now the variable listing all folders within a folder returns the following:

echo $SNAPSHOTS
2020-12-22_19H05/
2020-12-23_19H05/
2020-12-24_19H05/
2020-12-25_19H05/
2020-12-26_19H05/
2020-12-27_19H05/
2020-12-28_19H05/

Within each of those folders, for which the directory names change every day (oldest day gets deleted and today gets added), there is a file located at /etc/fstab, so 2020-12-22_19H05/etc/fstab as an example.

I need to edit that file, search for the fixed value "@home" and replace it with the variable value part of a fixed prefix string, like:

@snapshots/daily/home/$VARIABLE

The $VARIABLE = the directory names returned by the first variable listed above.

So within folder 2020-12-22_19H05/ the file /etc/fstab would be edited to replace @home by @snapshots/daily/home/2020-12-22_19H05 without the / at the end, it needs to be omited/truncated. And so on for all folders found by the first variable.

I am expecting sed and possibly % to be used, but I am really out of clue as to what to search on internet to 1-get an answer but mostly 2-understand the answer.

Thanks!

Frank
  • 1
  • I was able to edit each file within my variable with a FIXED value using "sudo sed s/"@home"/"@home2"/g $SNAPSHOTS". But I need to replace "@home2" by "$SNAPSHOTS" value. – Frank Dec 29 '20 at 02:09
  • I meant editing "@home" by "$SNAPSHOTS", not editing "@home2". I am passed the 5mins editing delay. :) – Frank Dec 29 '20 at 02:27