Echo current filename into a text file ubuntu? - linux

I normally just browse around and not looking to post questions however I am currently learning how to shell script and I've fallen into a pickle.
At the moment I have a structure of:
Main
---Hub1
---Hub2
---Hub3
---Hub4
All the way to Hub20.
What i want the structure to be is:
Main
---Hub1
--------Notes_1.txt >> "The <file_name> belongs to <user> and was created in Hub1"
---Hub2
--------Notes_2.txt >> "The <file_name> belongs to <user> and was created in Hub2"
and so on.
At the moment my code is looking like this
i=1
until (($i>20))
filename="~/Main/Hub${i}/Notes_$i.txt"
do
touch ~/Main/Hub${i}/Notes_$i.txt
echo "The $(basename -- "$filename") belongs to $USER was created in the Hub${i}" >> ~/Main/Hub${i}.txt
((i++))
done
Its not doing what it needs to be doing and I just cant figure out what I am doing wrong. I am aware it's not formatted right. It may be a simply solution or maybe I am completely off. I want to get it working before I start moving it around. Any advice would be great. Thank you!

You can use a brace range instead of until.
Don't put the pathname in quotes, that prevents expanding ~.
You need $ before filename in the echo statement to expand the variable.
for i in {1..20}; do
filename=~/Main/Hub${i}/Notes_$i.txt
touch "$filename"
echo "The $(basename -- "$filename") belongs to $USER was created in the Hub${i}" >> ~/Main/Hub${i}.txt
done

Related

Call an interactive subscript and save its output to variable

I currently have a Perl script (that I can't edit) that asks the user a few questions, and then prints a generated output to stdout. I want to make another script that calls this script, allows the user to interact with it as normal, and then stores the output from stdout to a variable.
Here's a really simple example of what I'm trying to accomplish:
inner.pl
#!/usr/bin/perl
print "Enter a number:";
$reply = <>;
print "$reply";
outer.sh (based on the answer by Op De Cirkel here)
#!/bin/bash
echo "Calling inner.pl"
exec 5>&1
OUTPUT=$(./inner.pl | tee >(cat - >&5))
echo "Retrieved output: $OUTPUT"
Desired output:
$ ./outer.sh
Calling inner.pl
Enter a number: 7
7
Retrieved output: 7
However, when I try this, the script will output Calling inner.pl before "hanging" without printing anything from inner.sh.
I've found a bit of a workaround by using the script command to store the entire inner.sh exchange to a temporary file, and then using sed and the like to modify it to my needs. But making temporary files for something fairly trivial like that doesn't make a ton of sense (not to mention script likes to add time stamps and \rs to everything). Is there any non-script way to accomplish this?
The answer is simpler than that. Simply redirect inner's output to a variable with $():
#!/bin/bash
echo "Calling inner.sh"
OUTPUT=$(./inner.sh)
echo "Retrieved output: $OUTPUT"
EDIT:
Now, if there's user interaction with the output in inner.sh (example inner.sh asks user for a number, prints any operation with it and asks the user to input a new value based on that printed result). Then the better is a temporary file like this:
#!/bin/bash
echo "Calling inner.sh"
TMPFILE=`mktemp`
./inner.sh | tee "$TMPFILE"
OUTPUT=$(cat "$TMPFILE")
rm "$TMPFILE"
echo "Retrieved output: $OUTPUT"

Bash write into file that is named by a variable

I am working on creating a simple script to make it easy to set up a virtual host on Apache server. Currently I don't seem to be able to write the config file because it's in a variable. How do I get around it. Here is my code that does not work.
siteConf="/etc/apache2/sites-available/$domain.conf"
echo "creating conf file"
echo "<VirtualHost *:80>" >> $siteConf
echo "ServerName *.$domain" >> $siteConf
echo "DocumentRoot $publicHtmlLoc" >> $siteConf
echo "DirectoryIndex index.php" >> $siteConf
echo "ServerAlias $database.newphp.junglecoders.dk" >> $siteConf
echo "</VirtualHost>" >> $siteConf
I am running the script with the bash command.
Edit: The Error i get is this
$siteConf: ambiguous redirect
Domain comes from here:
echo "Write websiter url example.com, no sub dir allowed"
read -p "Name: " domain
As suggested in comments its the path that is wrong, i tried to echo out the variable and i can see it has removed the '.' chars from some reason and left a space instead, why would the script do that ?
Edit2:
Was using IFS earlier in the script, to split the the domain name
The code looks as if it should work. You might do better with
{
echo "<VirtualHost …>"
…
echo "</VirtualHost>"
} > $siteConf
(or >> $siteConf if you really want to add to the existing file). That does a single redirection for all the output, and truncates the file. It is also a good idea as a general rule to enclose uses of variables in double quotes:
} > "$siteConf"
Basic debugging for shell scripts:
What do you get from bash -x your-script.sh?
You get 'ambiguous redirect' when the variable named doesn't exist or is empty, or if it expands to two or more words. That suggests that the first line of your script isn't an accurate representation of what you've got, but it is hard to guess how you've got it wrong. Misspelled name, or an unwanted space are probably the most likely, but it could be something else.
Alright looks like I needed to wrap it like in quotes like in the answer Getting an 'ambiguous redirect' error that antak suggested.
That's a good question to cross-reference. At one point, this question was closed as a duplicate of it, but the issue here turned out to be about IFS being set, which is not an alternative source of trouble identified in that other question.
Have you gone messing with IFS at any point in the script?
Yes — been doing IFS for splitting the URL into parts.
Note that:
set_with_spaces="name1 name2"
echo Hi >> $set_with_spaces
yields
bash: $set_with_spaces: ambiguous redirect too.
Two names were generated from one variable.
$ IFS=.
$ domain=abc.def.ghi.jkl
$ echo $domain
abc def ghi jkl
$ echo "$domain"
abc.def.ghi.jkl
$ IFS=$' \t\n'
$ echo $domain
abc.def.ghi.jkl
$
If you have been messing with IFS, then its current value is probably altering how the names are being interpreted. Reinstate it to its default value (blank, tab, newline):
IFS=$' \t\n'

How to execute Linux shell variables within double quotes?

I have the following hacking-challenge, where we don't know, if there is a valid solution.
We have the following server script:
read s # read user input into var s
echo "$s"
# tests if it starts with 'a-f'
echo "$s" > "/home/user/${s}.txt"
We only control the input "$s". Is there a possibility to send OS-commands like uname or do you think "no way"?
I don't see any avenue for executing arbitrary commands. The script quotes $s every time it is referenced, so that limits what you can do.
The only serious attack vector I see is that the echo statement writes to a file name based on $s. Since you control $s, you can cause the script to write to some unexpected locations.
$s could contain a string like bob/important.txt. This script would then overwrite /home/user/bob/important.txt if executed with sufficient permissions. Sorry, Bob!
Or, worse, $s could be bob/../../../etc/passwd. The script would try to write to /home/user/bob/../../../etc/passwd. If the script is running as root... uh oh!
It's important to note that the script can only write to these places if it has the right permissions.
You could embed unusual characters in $s that would cause irregular file names to be created. Un-careful scripts could be taken advantage of. For example, if $s were foo -rf . bar, then the file /home/user/foo -rf . bar.txt would be created.
If someone ran for file in /home/user; rm $file; done they'd have a surprise on their hands. They would end up running rm /home/user/foo -rf . bar.txt, which is a disaster. If you take out /home/user/foo and bar.txt you're left with rm -rf . — everything in the current directory is deleted. Oops!
(They should have quoted "$file"!)
And there are two other minor things which, while I don't know how to take advantage of them maliciously, do cause the script to behave slightly differently than intended.
read allows backslashes to escape characters like space and newline. You can enter \space to embed spaces and \enter to have read parse multiple lines of input.
echo accepts a couple of flags. If $s is -n or -e then it won't actually echo $s; rather, it will interpret $s as a command-line flag.
Use read -r s or any \ will be lost/missinterpreted by your command.
read -r s?"Your input: "
if [ -n "${s}" ]
then
# "filter" file name from command
echo "${s##*/}" | sed 's|^ *\([[:alnum:]_]\{1,\}\)[[:blank:]].*|/home/user/\1.txt|' | read Output
(
# put any limitation on user here
ulimit -t 5 1>/dev/null 2>&1
`${read}`
) > ${OutPut}
else
echo "Bad command" > /home/user/Error.txt
fi
Sure:
read s
$s > /home/user/"$s".txt
If I enter uname, this prints Linux. But beware: this is a security nightmare. What if someone enters rm -rf $HOME? You'd also have issues with commands containing a slash.

Linux: Use parameter as file shortcut

Cheers everyone :)
I'm trying to make a linux script. This script shall be called with one parameter, a file stored in my home directory. I can't seem to use
cat $var1 >> $1
So i have this variable $var1 and I want to save it in a file that does exist and its name is given in $1
Anyone help me please!
The cat command shows the contents of a file.
Unless the value of $var1 is a file that you want to 'copy' to $1, it won't work (probably gives a 'file not found' kind of error).
The easiest solution, I can think of, is to echo the variable:
echo "$var1" >> "$1"
As stated by #glglgl it is better to put the variable between double quotes. They prevent spaces messing up the command as they split a parameter into multiple parameters
Then you want to create a script that saves things in the file you indicate as a parameter.
file_name=$1 #you get the parameter
...do things...
echo "everything you've done" >> $file_name #case want to append
echo "everything you've done" > $file_name #case want to overwrite

Linux script trying to remove the 'return' in a file

I'm trying to write a pretty basic script in Linux shell but I'm still learning. Basically, everything is good to go except one part. I direct two outputs into the same file, e.g.:
echo `losetup -a` > partitionfile
echo "p1" >> partition final
Basically, I need to add the letter/number "p1" to the end of whatever is written in the file.
The problem is, it ends up being read (cat partitionfile) as:
/dev/loop0
p1
I need it on the same line to it reads out as:
/dev/loop0p1
There has to be a way to fix this, I just don't know it. Any help would be much appreciated!
Thanks!
I would go for:
echo "$(losetup -a)p1" > partitionfile
For an example, see the following transcript:
pax> echo "$(echo xyzzy_)p1"
xyzzy_p1
The xyzzy_ is the output of the inner echo command (which in your case would be losetup) and the outer echo command appends p1.
Hi Actually the correct option of echo to achieve this is "\c"
\c Keeps the cursor on the same line.
However you cannot use \c unless you have enabled it with
-e
Thus your code should be something like this ...
echo -e "`losetup -a` \c" > partitionfile
echo "p1" >> partition final
this will write in partitionfile as
< output of losetup -a > p1
everything on same line.
You can pass -n flag to the first echo statement to not print the trailing new line.
Ref: http://linux.die.net/man/1/echo

Resources