Extracting file using bash script -- error occur - linux

I have created a bash script which will extract a tar.gz file which is decompressed 5 times and remain the last tar.gz file decompressed. When I execute this acript I got this error line 26: 0++: syntax error: operand expected (error token is "+") . Please see below script.
i=0
for tarfile in *.tar.gz
do
$(($i++))
[ $i = 5 ] && break
tar -xf "$tarfile"
done
What is the error about and what is the correct way to solve my problem which is extracting the file five times and remain the last file decompressed. Thanks in advance for those who help.

you want to change $(($i++)) to ((i++)). see https://askubuntu.com/questions/385528/how-to-increment-a-variable-in-bash
Let's deconstruct $(($i++)). going outwards, $i expands to 0. so we have the expression $((0++)). 0 can't be incremented since it is a value, not a variable. so you get your error message line 26: 0++: syntax error: operand expected (error token is "+").
The reason to use ((i++)) without a $ at the front is that the $ at the front would actually evaluate i. You don't want i to be evaluated here, you just want i to be incremented. (h/t the other guy)

Related

Getting "ambiguous redirect" error in my shell script [duplicate]

The following line in my Bash script
echo $AAAA" "$DDDD" "$MOL_TAG >> ${OUPUT_RESULTS}
gives me this error:
line 46: ${OUPUT_RESULTS}: ambiguous redirect
Why?
Bash can be pretty obtuse sometimes.
The following commands all return different error messages for basically the same error:
$ echo hello >
bash: syntax error near unexpected token `newline`
$ echo hello > ${NONEXISTENT}
bash: ${NONEXISTENT}: ambiguous redirect
$ echo hello > "${NONEXISTENT}"
bash: : No such file or directory
Adding quotes around the variable seems to be a good way to deal with the "ambiguous redirect" message: You tend to get a better message when you've made a typing mistake -- and when the error is due to spaces in the filename, using quotes is the fix.
Do you have a variable named OUPUT_RESULTS or is it the more likely OUTPUT_RESULTS?
michael#isolde:~/junk$ ABC=junk.txt
michael#isolde:~/junk$ echo "Booger" > $ABC
michael#isolde:~/junk$ echo "Booger" >> $ABB
bash: $ABB: ambiguous redirect
michael#isolde:~/junk$
put quotes around your variable. If it happens to have spaces, it will give you "ambiguous redirect" as well. also check your spelling
echo $AAAA" "$DDDD" "$MOL_TAG >> "${OUPUT_RESULTS}"
eg of ambiguous redirect
$ var="file with spaces"
$ echo $AAAA" "$DDDD" "$MOL_TAG >> ${var}
bash: ${var}: ambiguous redirect
$ echo $AAAA" "$DDDD" "$MOL_TAG >> "${var}"
$ cat file\ with\ spaces
aaaa dddd mol_tag
I've recently found that blanks in the name of the redirect file will cause the "ambiguous redirect" message.
For example if you redirect to application$(date +%Y%m%d%k%M%S).log and you specify the wrong formatting characters, the redirect will fail before 10 AM for example. If however, you used application$(date +%Y%m%d%H%M%S).log it would succeed. This is because the %k format yields ' 9' for 9AM where %H yields '09' for 9AM.
echo $(date +%Y%m%d%k%M%S) gives 20140626 95138
echo $(date +%Y%m%d%H%M%S) gives 20140626095138
The erroneous date might give something like:
echo "a" > myapp20140626 95138.log
where the following is what would be desired:
echo "a" > myapp20140626095138.log
Does the path specified in ${OUPUT_RESULTS} contain any whitespace characters? If so, you may want to consider using ... >> "${OUPUT_RESULTS}" (using quotes).
(You may also want to consider renaming your variable to ${OUTPUT_RESULTS})
If your script's redirect contains a variable, and the script body defines that variable in a section enclosed by parenthesis, you will get the "ambiguous redirect" error. Here's a reproducible example:
vim a.sh to create the script
edit script to contain (logit="/home/ubuntu/test.log" && echo "a") >> ${logit}
chmod +x a.sh to make it executable
a.sh
If you do this, you will get "/home/ubuntu/a.sh: line 1: $logit: ambiguous redirect". This is because
"Placing a list of commands between parentheses causes a subshell to
be created, and each of the commands in list to be executed in that
subshell, without removing non-exported variables. Since the list is
executed in a subshell, variable assignments do not remain in effect
after the subshell completes."
From Using parenthesis to group and expand expressions
To correct this, you can modify the script in step 2 to define the variable outside the parenthesis: logit="/home/ubuntu/test.log" && (echo "a") >> $logit
I got this error when trying to use brace expansion to write output to multiple files.
for example: echo "text" > {f1,f2}.txt results in -bash: {f1,f2}.txt: ambiguous redirect
In this case, use tee to output to multiple files:
echo "text" | tee {f1,f2,...,fn}.txt 1>/dev/null
the 1>/dev/null will prevent the text from being written to stdout
If you want to append to the file(s) use tee -a
If you are here trying to debug this "ambiguous redirect" error with GitHub Actions. I highly suggest trying it this way:
echo "MY_VAR=foobar" >> $GITHUB_ENV
The behavior I experienced with $GITHUB_ENV is that, it adds it to the pipeline environment variables as my example shows MY_VAR
I just had this error in a bash script. The issue was an accidental \ at the end of the previous line that was giving an error.
One other thing that can cause "ambiguous redirect" is \t \n \r in the variable name you are writing too
Maybe not \n\r? But err on the side of caution
Try this
echo "a" > ${output_name//[$'\t\n\r']}
I got hit with this one while parsing HTML, Tabs \t at the beginning of the line.
This might be the case too.
you have not specified the file in a variable and redirecting output to it, then bash will throw this error.
files=`ls`
out_file = /path/to/output_file.t
for i in `echo "$files"`;
do
content=`cat $i`
echo "${content} ${i}" >> ${out_file}
done
out_file variable is not set up correctly so keep an eye on this too.
BTW this code is printing all the content and its filename on the console.
if you are using a variable name in the shell command, you must concatenate it with + sign.
for example :
if you have two files, and you are not going to hard code the file name, instead you want to use the variable name
"input.txt" = x
"output.txt" = y
then ('shell command within quotes' + x > + y)
it will work this way especially if you are using this inside a python program with os.system command probably
In my case, this was a helpful warning, because the target variable (not the file) was misspelled and did not exist.
echo "ja" >> $doesNotExist
resulting in
./howdy.sh: line 4: $doesNotExist: ambiguous redirect
For my case, if I specify the output file via a env (e.g $ENV_OF_LOG_FILE), then will get the error ambiguous redirect.
But, if I use plain text as file path (e.g /path/to/log_file), then there is no error.

How do you append a string built with interpolation of vars and STDIN to a file?

Can someone fix this for me.
It should copy a version log file to backup after moving to a repo directory
Then it automatically appends line given as input to the log file with some formatting.
That's it.
Assume existence of log file and test directory.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG |
VHENTRY="- **${LOGDATE}** | ${VHMSG}"
cat ${VHENTRY} >> versionlog.MD
shell output
virufac#box:~/Git/test$ ~/.logvh.sh
MSG > testing script
EOF
EOL]
EOL
e
E
CTRL + C to get out of stuck in reading lines of input
virufac#box:~/Git/test$ cat versionlog.MD
directly outputs the markdown
# Version Log
## version 0.0.1 established 01-22-2020
*Working Towards Working Mission 1 Demo in 0.1 *
- **01-22-2020** | discovered faker.Faker and deprecated old namelessgen
EOF
EOL]
EOL
e
E
I finally got it to save the damned input lines to the file instead of just echoing the command I wanted to enter on the screen and not executing it. But... why isn't it adding the lines built from the VHENTRY variable... and why doesn't it stop reading after one line sometimes and this time not. You could see I was trying to do something to tell it to stop reading the input.
After some realizing a thing I had done in the script was by accident... I tried to fix it and saw that the | at the end of the read command was seemingly the only reason the script did any of what it did save to the file in the first place.
I would have done this in python3 if I had know this script wouldn't be the simplest thing I had ever done. Now I just have to know how you do it after all the time spent on it so that I can remember never to think a shell script will save time again.
Use printf to write a string to a file. cat tries to read from a file named in the argument list. And when the argument is - it means to read from standard input until EOF. So your script is hanging because it's waiting for you to type all the input.
Don't put quotes around the path when it starts with ~, as the quotes make it a literal instead of expanding to the home directory.
Get rid of | at the end of the read line. read doesn't write anything to stdout, so there's nothing to pipe to the following command.
There isn't really any need for the VHENTRY variable, you can do that formatting in the printf argument.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG
printf -- '- **%s** | %s\n' "${LOGDATE}" "$VHMSG" >> versionlog.MD

Test if a file exists

I struggle with the examples given if a file exists.
I want to check if multiple files exists in order to perform further operations.
ls -al:
-rwxrwxrwx 1 root tomcat 6 Dec 16 11:25 documents_2019-12-12.tar.gz
echo < [ -e ./documents_2019-12-12.tar.gz ]:
bash: [: No such file or directory
Can somebody tell me what i'm doing wrong?
Edit:
I have a backup direcory with two files:
database_date.sql
documents_date.tar.gz
I need to check if both files for a given date are available. The directory shall contain these file-pairs for several dates.
What you have here is a misunderstanding of where specific syntax is used. The [ -e ./documents_2019-12-12.tar.gz ] part of your command is syntax specific to the if clause in bash. Here's an example
if [ -e ./documents_2019-12-12.tar.gz ]
then
echo "File Exists!"
fi
The square brackets [] are used to surround the check being performed by the if statement and the -e flag is specific to these if checks. More info here http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html
To explain the error you're seeing, the < operator takes a file to the right and feeds the contents to the command on the left. In your case the < sees the [ as the thing on the right so we try and read it as a file. Such a file doesn't exist so bash helpfully tells you that there's an error (the bash: [: No such file or directory bit) and then quits out.

Why does read throw an error in bash but works fine?

This bash script writes an array to a file and then reads the file back into a different array. (This is useful for array-based communication between scripts.) However, a strange, non-reported error is trapped by the IFS line (line 12). Why?
#!/bin/bash
# eso-error-ic
trap 'echo Error trapped, with code $?, on line ${LINENO}' ERR
# write data to a file
arr=(0 abc) && printf "%s\n" "${arr[#]}" > eso.out
# read data from the file into an array
# throws an error!!
IFS=$'\n' read -d '' -a new_arr < eso.out
# but it worked...
echo ${new_arr[0]}
echo ${new_arr[1]}
Script output:
Error trapped, with code 1, on line 12
0
abc
What's missing is any sort of message displayed when the error is produced. All you get is the message from the trap but no message about what the error is.
In other words, the IFS/read line produces an error, which is trapped, but no error message is displayed and the line properly reads the file into an array variable. It works, reports no error, but an "error" is trapped.
If you comment out the trap line OR switch to the command/eval/cat approach to reading a file into an array (as suggested here), no error is trapped. Here is what the command/eval/cat line would look like for this script (to replace line 12):
IFS=$'\n' GLOBIGNORE='*' command eval 'new_arr=($(cat eso.out))'
The error comes from not receiving the delimiter that read was expecting. I get the same with
read -d x variable <<<"hello"
If I change the input to "hellox" the error disappears.
As mentioned by #Aserre, a detailed analys is at our Unix & Linux sister site and as pointed out by #CharlesDuffy a common workaround is
read variable || [[ $variable ]]
which is used even without -d to cope with files which might lack the final terminating newline.

I can't get my bash script to run

This is the script that I used to that will not run, but I am hoping someone can help me figure out what the issue is. I am new to unix
#!/bin/bash
# cat copyit
# copies files
numofargs=$#
listoffiles=
listofcopy=
# Capture all of the arguments passed to the command, store all of the arguments, except
# for the last (the destination)
while [ "$#" -gt 1 ]
do
listoffiles="$listoffiles $1"
shift
done
destination="$1"
# If there are less than two arguments that are entered, or if there are more than two
# arguments, and the last argument is not a valid directory, then display an
# error message
if [ "$numofargs" -lt 2 -o "$numofargs" -gt 2 -a ! -d "$destination" ]
then
echo "Usage: copyit sourcefile destinationfile"
echo" copyit sourcefile(s) directory"
exit 1
fi
# look at each sourcefile
for fromfile in $listoffiles
do
# see if destination file is a directory
if [ -d "$destination" ]
then
destfile="$destination/`basename $fromfile`"
else
destfile="$destination"
fi
# Add the file to the copy list if the file does not already exist, or it
# the user
# says that the file can be overwritten
if [ -f "$destfile" ]
then
echo "$destfile already exist; overwrite it? (yes/no)? \c"
read ans
if [ "$ans" = yes ]
then
listofcopy="$listofcopy $fromfile"
fi
else
listofcopy="$listofcopy $fromfile"
fi
done
# If there is something to copy - copy it
if [ -n "$listofcopy" ]
then
mv $listofcopy $destination
fi
This is what I got and it seems that the script didn't execute all though I did invoke it. I am hoping that someone can help me
[taniamack#localhost ~]$ chmod 555 tryto.txt
[taniamack#localhost ~]$ tryto.txt
bash: tryto.txt: command not found...
[taniamack#localhost ~]$ ./tryto.txt
./tryto.txt: line 7: $'\r': command not found
./tryto.txt: line 11: $'\r': command not found
./tryto.txt: line 16: $'\r': command not found
./tryto.txt: line 43: syntax error near unexpected token `$'do\r''
'/tryto.txt: line 43: `do
Looks like your file contains Windows new line formatting: "\r\n". On Unix, a new line is just "\n". You can use dos2unix (apt-get install dos2unix), to convert your files.
Also have a look at the chmod manual (man chmod).
Most of the time i just use chmod +x ./my_file to give execution rights
I see a few issues. First of all, a mode of 555 means that no one can write to the file. You probably want chmod 755. Second of all, you need to add the current directory to your $PATH variable. In Windows, you also have a %PATH%, but by default the current directory . is always in %PATH%, but in Unix, adding the current directory is highly discouraged because of security concerns. The standard is to put your scripts under the $HOME/bin directory and make that directory the last entry in your $PATH.
First of all: Indent correctly. When you enter a loop or an if statement, indent the lines by four characters (that's the standard). It makes it much easier to read your program.
Another issue is your line endings. It looks like some of the lines have a Windows line ending on them while most others have a Unix/Linux/Mac line ending. Windows ends each line with two characters - Carriage Return and Linefeed while Unix/Linux/Mac end each line with just a Linefeed. The \r is used to represent the Carriage Return character. Use a program editor like vim or gedit. A good program editor will make sure that your line endings are consistent and correct.

Resources