Compressing using tar with bash script : Line n is a directory - bash

I'm new with bash script and now trying to make a back-up file using it. What I'm facing is below script (line 47 in my bash file),
$(tar -czvPf ${folder_backup}/rajal/backup.tgz -C /var/www/tmk/app .)
always gimme error on the shell ./test: line 47: ./: Is a directory, while it works on Terminal, nicely.
FYI, folder app is folder with files and subfolders.
Could someone help me out? Thank you for any help.

$(command)
means: execute command and return its output. To illustrate, it is very often used like this:
result=$(foo 4 123)
After this is evaluated, result will hold whatever the command foo 4 123 output.
If you use that construct directly - not as an argument to another command, or in a variable assignment, the shell will try to execute the output of the command. While this is sometimes wanted, it often is not, and that's what you're seeing.
So just remove the $( ) from your command and run tar directly. If you want to capture the output of tar, either redirect it to a file or use the construct above.
Do note that $(command) and ${env_var_name} are completely different. Syntax matters.

Like #Mat Why do you have $( ) around the tar?, so i just removed it and it is working now :D

Related

How to create one output file for each file passed to a loop in bash?

I have a file that I pass to a bash command that will create an output in a loop like so:
for file in /file/list/*
do
command
done
I wish to save the output that would have gone to standard out of each loop to a text file in my working directory. Currently I am trying this:
for file in /file/list/*
do
command | tee "$file_command output.txt"
done
What I expect to see are new files created in my current directory titled file1.txt_commandoutput.txt, file2.txt_commandoutput.txt, etc. The output of the command should be saved as a different file for each file. However I get only one file created and it's called ".txt" and can't be opened by any standard software on Mac. I am new to bash scripting, so help would be much appreciated!
Thanks.
Your problem comes from the variable name you're using:
"$file_command_output.txt" looks for a variable named file_command_output (the dot cannot be in the variable name, but the alphanumerical characters and the underscore all can).
What you're looking for is "${file}_command_output.txt" to make the variable name more explicit.
You have two issues in your script.
First, the wrong parameter/variable is expanded (file_command instead of file) because it's followed by a character that can be interpreted as part of the name (the underscore, _). To fix it, enclose the parameter name in braces, like this: ${file}_command (see Shell Parameter Expansion in bash manual).
Second, even with fixed variable name expansion, the file won't be created in your working directory, because the file holds an absolute pathname (/file/list/name). To fix it, you'll have to strip the directory from the pathname. You can do that with either basename command, or even better with a modified shell parameter expansion that will strip the longest matching prefix, like this: ${file##*/} (again, see Shell Parameter Expansion, section on ${parameter##word}).
All put together, your script now looks like:
#!/bin/bash
for file in /file/list/*
do
command | tee "${file##*/}_command output.txt"
done
Also, to just save the command output to a file, without printing it in terminal, you can use a simple redirection, instead of tee, like this: command > "${file##*/}_com...".
If you are not aware of xargs, try this:
$ ls
file
$ cat > file
one
two
three
$ while read this; do touch $this; done < ./file
$ ls
file one three two

Iteration in bash is not working

I am trying to run the next code on bash. It is suppose to work but it does not.
Can you help me to fix it? I am starting with programming.
The code is this:
for i in {1:5}
do
cd path-to-folder-number/"$i"0/
echo path-to-folder-number/"$i"0/
done
EXAMPLE
I want to iterate over folders which have numbers (10,20..50), and so it changes directory from "path-to-folder-number/10/" to "path-to-folder-number/20/" ..etc
I replace : with .. but it is not working yet. When the script is applied i get:
can't cd to path-to-folder-number/{1..5}0/
I think there are three problems here: you're using the wrong shell, the wrong syntax for a range, and if you solved those problems you may also have trouble with successive cds not doing what you want.
The shell problem is that you're running the script with sh instead of bash. On some systems sh is actually bash (but running in POSIX compatibility mode, with some advanced features turned off), but I think on your system it's a more basic shell that doesn't have any of the bash extensions.
The best way to control which shell a script runs with is to add a "shebang" line at the beginning that says what interpreter to run it with. For bash, that'd be either #!/bin/bash or #!/usr/bin/env bash. Then run the script by either placing it in a directory that's in your $PATH, or explicitly giving the path to the script (e.g. with ./scriptname if you're in the same directory it's in). Do not run it with sh scriptname, because that'll override the shebang and use the basic shell, and it won't work.
(BTW, the name "shebang" comes from the "#!" characters the line starts with -- the "#" character is sometimes called "sharp", and "!" is sometimes called "bang", so it's "sharp-bang", which gets abbreviated to "shebang".)
In bash, the correct syntax for a range in a brace expansion is {1..5}, not {1:5}. Note that brace expansions are a bash extension, which is why getting the right shell matters.
Finally, a problem you haven't actually run into yet, but may when you get the first two problems fixed: you cd to path-to-folder-number/10/, and then path-to-folder-number/20/, etc. You are not cding back to the original directory in between, so if the path-to-folder-number is relative (i.e. doesn't start with "/"), it's going to try to cd to path-to-folder-number/10/path-to-folder-number/20/path-to-folder-number/30/path-to-folder-number/40/path-to-folder-number/50/.
IMO using cd in scripts is generally a bad idea, because there are a number of things that can go wrong. It's easy to lose track of where the script is going to be at which point. If any cd fails for any reason, then the rest of the script will be running in the wrong place. And if you have any files specified by relative paths, those paths become invalid as soon as you cd someplace other than the original directory.
It's much less fragile to just use explicit paths to refer to file locations within the script. So, for example, instead of cd "path-to-folder-number/${i}0/"; ls, use ls "path-to-folder-number/${i}0/".
For up ranges the syntax is:
for i in {1..5}
do
cd path-to-folder-number/"$i"0/
echo $i
done
So replace the : with ..
To get exactly what you want you can use this:
for i in 10 {20..50}
do
echo $i
done
You can also use seq :
for i in $(seq 10 10 50); do
cd path-to-folder-number/$i/
echo path-to-folder-number/$i/
done

How to make a shell script take an argument passed in the command line?

I have a shell script (count_reviews.sh) that contains the following:
#!/bin/bash
grep -c "Author" "#1"
I have tried using "$1" as I found that this takes the first argument in the command line but I still get the error mentioned below. I have also used chmod +x to make my file executable.
The script counts the number of times "Author" appears in the file. I am required to be able to make the command line take an input of "% ./count_reviews.sh hotel_72572.dat" where hotel_72572.dat is an example file name. The number of times author appears will then be printed out underneath. When I do this however, I am getting an error -bash: fg: %: no such job. What is causing this and how do I fix it? My count_reviews.sh file is in the same directory as all of my hotel data files if that matters.
You should indeed use $1, but when you try to run your script just use ./your_script.sh your_argument don't add the % in the beginning.

Difference between typing a shell command, and save it to a file and using `cat myfile` to execute it?

I have an rsync command that works as expected when I type it directly into a terminal. The command includes several --include='blah' and --exclude='foo' type arguments. However, if I save that command to a one-line file called "myfile" and I try `cat myfile` (or, equivalently $(cat myfile)), the rsync command behaves differently.
I'm sure it is the exact same command in both cases.
Is this behavior expected/explainable?
I've found the answer to this question. The point is that the cat command takes the contents of the file and treats it like a string. Any string operators (like the escape operator, ) are executed. Then, the final string output is what is passed to a command via the backticks.
As a solution, I've just made "myfile" a shell script that I can execute rather than trying to use cat.

What is the difference if a shell script has ".sh" extension or not?

I have two identical shell script: A.sh , A , I want to know what is the difference ?
You can even call it A.txt. Then give it execute permission and run it. If you give a .sh extension then others can easily identify that its a shell script.
As far as Linux based operating system, the extension does not make any special meaning. You can have any name for your file. You can execute the script with respective runtime.
For bash, sh sample.txt
For Python, python sample.txt
For NodeJS, node sample.txt
For better maintainability of the code, you have to name your filename with proper extension like .sh, .py, .js and etc.
Actually,
Once your /path/to/anyfunnyfilename script has execution privileges, if you want to run it without calling the interpreter, you can have the FIRST line of your script like this:
#!/usr/bin/bash
code line 1
code line 2
...
code line n
it also apply for
#!/bin/perl
your perl code here
Another example:
#!/bin/python
your python code here
#!/bin/expect
your expect code here
And so on..
Hope this helps..

Resources