What a "funny" error in the first code , it has already happened to me and it has bothered me for days. I'm sure it's because of the line breaks.
See what type of line breaks this file has set to sublime in "View" > "Line endings". There it tells you if it is Unix or Windows for Mac. You can select the Unix type there but, in case it happens again and you do not have a comfortable editor, you can use a program called dos2unix
with something of the following type:
$ dos2unix <tu archivo>
Or you can do something similar with sed
or tr
:
$ sed -i 's/\r//g' <tu archivo>
or
$ tr -d '\r' < <tu archivo> > archivo_nuevo
The explanation is that conventions for control characters were established for each group of operating systems. In the case of the line break, Windows follows the convention of using the escape sequence \r\n
and those of the Linux family use the \n
, then those characters are not visible to the naked eye and cause havoc.
You can see more information here:
link
What makes sed
and tr
in the suggestions I put is to delete the CR (Carriage Return) or the \r
.
Instead dos2unix
, in addition to doing this, you can convert the encoding from DOS to Unix or from Windows unicode to Unix unicode.
What should I do if I encounter problems like that from strangers?
Well, if you already have intuition and you are sure that the part of your code that you want to debug is fine, use cat
with the flag -A
to that file, this will allow you to see non-printable characters using the notations "^" and "M-", to see line breaks, tabs, etc.
For example:
$ cat -A archivo_raro
Whatever ^I
are tabs, whatever ^M
are carriage return's "\ r" and whatever $
is the line feed (or new line ) "\ n". Now, if you look closely at the error, it says something like "... it's not a valid identifier ..." It seems to be that the cursor is traversed, since it seems to truncate a "valid (in line) ea" and then you write about things ... well that's what the carriage return does, there you can "feel" one of its effects.
In the second code, it seems that the problem is similar to the first one, around the "DOS" type line breaks. But in your code I see anomalies like that you do not put the token then
after the if
and also do not put a token that indicates an evaluation as they are [, test, [[, ((
, you put immediately "$ ano", that is, it will take as a token to evaluate what you entered and it is very likely that it does not mean anything to for bash. Furthermore, if, after pure chance, something means, for example, that you enter an "ls", the token !=
by itself does not mean anything to bash. Precisely for that reason it needs to be inside an evaluator, so that the evaluator understands tokens like "==", "!=", "&", "||".
The correct version would be something of the style:
( this is wrong, see the update below )
if [[ $ano != [1-9999] ]]; then
I put the built-in [[
instead of the [
because otherwise the evaluator could not understand the range expression "[1-9999]" and would always return false to less that you enter the chain to dry "[1-9999]". That is, tokens "!=" And "==" within []
compare strings, but within [[]]
compare the value on the left with a pattern, from the matching list of patterns, from the right.
For more information about this you can read in link and in link
Summing up. Remove the characters "\ r" or change the line breaks from Windows to Unix, change your premises if a != b
using the appropriate token, in this case [[
, in addition to using the token ; then
or removing the ";" for a line break.
( this is wrong, see the update below )
if [[ $ano != [1-9999] ]]; then
As a suggestion, in your first code, you do not need to use inverted commas 'expresión'
since this way you run a process in a subshell, which is not necessary but it still works, you can remove those quotes.
Update 1
@nxnev raised a very important point, the way to compare that "avalé" is wrong because of a misinterpretation of my part to the manual.
That is to say, the form [[ $numero == [1-9] ]]
compares individual characters between a range, the problem that showed is that, in an example like:
[[ 10 == [1-9999] ]]
the evaluation would be false.
@nxnev also suggests an evaluation of the form
(( ano >= 1 && ano <= 9999 ))
or use the date
tool to work with dates.
Another proposal I came up with, which is somewhat cumbersome but shows another usefulness, is to use a regular expression.
[[ $ano =~ ^([1-9]|[0-9]{2}|[0-9]{3}|[0-9]{4})$ ]]