Help - Bash Script

Hi All, is there someone that can help me to understand this short code:

ls ${BACKUPS_FOLDER} | egrep "$(date +%Y -d "${i} year ago")-[0-9]{2}-[0-9]{2}" |sort -u | head n- 1

In particular, I would know the meaning of the part ... -[0-9]{2}-[0-9]{2} | sort -u | head -n 1 .
Thanks in advance.
Stefano

Hi Stefano,
What operating system are you using?

What version of the date utility are you using?

The command head n- 1 in your pipeline is always going to give you an error unless you have two files in your current working directory named n- and 1 . I assume that you intended to write head -n 1 instead of head n- 1 .

The meaning of the date -d option varies depending on the operating system you're using and the version of date you're using.

I would guess that the code is attempting to print the name of the last file in the directory named by the contents of the BACKUPS_FOLDER variable whose name contains a date of the form YYYY-MM-DD where YYYY is last year. Whether or not it succeeds will depend on the answers to the questions above and the names of the files in that directory.

1 Like

Hi Don and thank you so much for answer. I solved. The code posted is used, in that case, as a regular expression for a date in the format YYYY-MM-DD where YYYY is the current year, less the value of the variable {i}.

But now, I have one other issue very very difficult to understand (for me, naturally).

I would know what does mean this code

ls ${BACKUPDIR} | grep -v -e "$(echo -n $(listUniqueBackups) | sed "s//\\\|g")"

...
... in particular the two sections | grep -v -e "$echo -n ... and ... sed "s//\\\|g"

Thanks in advance.

PS The code is a command of linux bash script !

I don't have access to a Linux system to test this out, but I would expect the sed command at the end of the pipeline in your command substitution to fail due to a missing search pattern or a missing replacement pattern terminator. Are you sure you showed us the exact command that is being used?

On a standards conforming system, using echo -n output as input to sed would produced unspecified results, but processing an incomplete line of input might work with a GNU sed utility.

If you want our help with puzzles like this, please show us the relevant input variable contents (e.g. $BACKUPDIR and $listUniqueBackups ).

In this case, please also show us all of the output produced when you run the command:

echo -n $(listUniqueBackups) | sed "s//\\\|g"

Hi Don, belove the full text of a bash script I would use to manage a daily incremetal backup and delete the old ones. It should list - one after the other - Yearly, Montly, Weekly and Daily backups; after that, it should produce an unique total backups and, at the end, a list of backups to delete.
In the code I do not understand the final part; in particular:

ls ${CARTELLA_BACKUPS} | grep -v -e "$(echo -n "$(ListaBackupsUnica)" | sed "s//\\\|/g")"

and

BackupsDaCancellare | while read file_da_cancellare; do
rm -rf ${file_da_cancellare}

I have not still runned the code (so i can't show the output) because, first, I prefer realize what I am doing and mostly because I don't want mess up something!

Here is the total code (the variables and functions are expressed in Italy idioma):

#!/bin/bash
CARTELLA_BACKUPS=/mnt/BACKUP/
function ListaBackupsAnnui() {
for i in 0 1 2 3 4 5
do ls ${CARTELLA_BACKUPS} | egrep "$[0-9]{2}.[0-9]{2}.(date +%Y -d "${i} year ago")" | sort -u | head -n 1
done
}

function ListaBackupsMensili() {
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12
do ls ${CARTELLA_BACKUPS} | egrep "$[0-9]{2}.(date +%m -d "${i} month ago".%Y)" | sort -u | head -n 1
done
}

function ListaBackupsSettimanali() {
for i in 0 1 2 3 4
do ls ${CARTELLA_BACKUPS} | grep "$(date +%d -d "last monday -${i} weeks".%m.%Y)"
done
}

function ListaBackupsGiornalieri() {
for i in 0 1 2 3 4 5 6
do ls ${CARTELLA_BACKUPS} | grep "$(date +%d -d "-${i} day".%m.%Y)"
done
}

function ElencoComplessivo() {
ListaBackupsAnnui
ListaBackupsMensili
ListaBackupsSettimanali
ListaBackupGiornalieri
}

function ListaBackupsUnica() {
ElencoComplessivo | sort -u
}

function BackupsDaCancellare() {
ls ${CARTELLA_BACKUPS} | grep -v -e "$(echo -n "$(ListaBackupsUnica)" | sed "s//\\\|/g")"
}

cd ${CARTELLA_BACKUPS}
BackupsDaCancellare | while read file_da_cancellare; do
rm -rf ${file_da_cancellare}
done

Note that using yellow text on a white or gray background produces text that is almost invisible to an old guy like me with glaucoma.

Note that when you ask how a segment of code is going to behave, failing to EXACTLY copy the code about which you have questions wastes everybody's time (especially yours).

Note that when trying to get some code working, you usually NEED to set up a test bed where you have files with similar (preferably identical) names in file hierarchies that mimic the file hierarchies your script will be processing. For example, your script looks at files in the directory named by the variable CARTELLA_BACKUPS . Set up a copy of the files in that directory in another directory and change the way CARTELLA_BACKUPS is set to point to your test bed copy of those files while you are debugging your script. That way you can run your code and see what it does and not have to worry about destroying anything.

The shell's set -xv command is your friend when trying to figure out what code is doing. Once you issue that command, every command bash executes after that will be copied to your script's standard error output with all of the variables expanded so you (and us, if you need our help) can see clearly what the shell is trying to do for you.

Note that the on-line manual pages for your system are your friends too. The command man sed will display the manual page for sed on your system so you can read all about what it is supposed to do. If you look at the sed manual page you will find that the command I asked you to run:

echo -n $(listUniqueBackups) | sed "s//\\\|g"

will NEVER destroy anything in any file unless you redirect its output to a file or invoke it with the -i option (neither of which is the case here).

When I run that command on my system running macOS Mojave (version 10.14.5) without creating a function or utility named listUniqueBackups first, bash prints the diagnostic messages:

sed: 1: "s//\\|g": unterminated substitute in regular expression
bash: listUniqueBackups: command not found

If we use the real command that is in your script instead of the code you asked us about in post #3 in this thread and I feed it a fixed string containing a <newline> character, then I get the diagnostic message:

 echo a b c | sed "s//\\\|/g"
sed: first RE may not be empty

Maybe you'll get a similar diagnostic and you'll know that you have to actually supply an RE for sed to match. Maybe your version of sed will assign some meaning to an initial search for the empty RE (which is not mentioned on the Linux 2.6 commands sed man page and we'll be able to figure out what it is that it does, if you run the command and show us the output. If you're not willing to help me figure out how utilities behave on your system, then I'm afraid there is nothing I can do to help you.

Also note that if you change the line in your complete script:

rm -rf ${file_da_cancellare}

to:

echo rm -rf ${file_da_cancellare}

there won't be anything in your script that creates or removes any permanent files. It will be perfectly safe to run without even setting up a shadow file hierarchy.

Have you tried asking the person who gave you this code how the pieces of it that you don't understand are supposed to work?

Hi Don,

I changed the colors added by the original poster to black.

Hope that helps!