What's the difference between the parameters got by read and $1 - linux

echo -n "*.xcodeproj directory: ";
read fileDirectory;
echo -n $fileDirectory;
fileExtension="pbxproj";
find $fileDirectory -name "*.${fileExtension}";
It shows "find: XXXX"(fileDirectory) no such file or directory
However if I replace read fileDirectory by
fileDirectory=$1
It works.
So what's the difference?

$1 is the first argument passed to bash script or to a function inside the script
for example:
mybashfunction /dirtofind
inside the function if you write:
echo "$1"
It should print:
/dirtofind
Edit 1:
You must place the shebang in the beginning of you file
~$ cat a.sh
#!/bin/bash
echo -n "*.xcodeproj directory: ";
read fileDirectory;
echo -n $fileDirectory;
fileExtension="pbxproj";
find "$fileDirectory" -name "*.${fileExtension}";
~$ chmod +x a.sh
~$ ./a.sh
*.xcodeproj directory: /home
/home/home/leonardo/Qt/Tools/QtCreator/share/qtcreator/qbs/share/qbs/examples/cocoa-touch-application/CocoaTouchApplication.xcodeproj/project.pbxproj
/home/leonardo/Qt/Tools/QtCreator/share/qtcreator/qbs/share/qbs/examples/cocoa-application/CocoaApplication.xcodeproj/project.pbxproj
:~$
Works like charm here. Place the shebang
#!/bin/bash
Edit 2
Yes you can use eval. Your script will be like this:
#!/bin/bash
echo -n "*.xcodeproj directory: ";
read fileDirectory;
echo -n $fileDirectory;
fileExtension="pbxproj";
eval fileDirectory=$fileDirectory
find "$fileDirectory" -name "*.${fileExtension}";

read reads data from STDIN (by default), not from positional parameters (arguments).
As you are passing the data as first argument ($1) to the script, read would not catch it; it would catch the input you are providing interactively.
Just to note, you should quote your variable expansions to avoid word splitting and pathname expansion; these are unwanted in most cases.

Related

Evaluation of curly braces in Linux

I’ve noticed that we can use curly braces to make some of the commands much shorter as it is evaluated into list of arguments.
Input:
echo a{,b,c}
Output:
a ab ac
How do I force the same behaviour when the arguments are passed from the file?
Input:
cat file.txt | xargs echo
Output:
a{,b,c}
Expected output - same as in the previous example.
That {} expansion is a bash / zsh feature, as such then you need to explicitly run it thru any of these shells, in your case would be (using -I<STRING> to let xargs replace it in the string before running it):
cat file.txt |xargs -I# bash -c 'echo #'
xargs calls the echo as found in the $PATH, not the shell's builtin echo.
check the list of bash expansions: brace expansion happens first, so it won't get a chance to expand in that pipeline.
You'll have to do something like
while read -r line; do eval echo "$line"; done < file.txt
which exposes you to all kinds of nasty attacks if someone puts something malicious in that file.
Other than asking why would you want to do this... I offer the following:
add the string to a file:
echo 'a{,b,c}' > /tmp/foo
put the string in a variable:
export thing=`cat /tmp/foo`
eval the string:
eval $thing
If you had a bunch of these in a file then run the file through a loop and eval the loop value:
echo 'a{,b,c}' >> /tmp/foo
echo 'a{,b,c}' >> /tmp/foo
echo 'a{,b,c}' >> /tmp/foo
for i in `cat /tmp/foo`; do eval echo $i; done

Reading specifed file line and creating new directories from words that have been taking of that file

for file in $*
head -n 1 $file | while read folder
do
mkdir $directory $folder
done
Hello guys, I'm having problem with my script. What I want to do is: read first line from my specifed file and create new directories in my specifed directory from words that i have taken from that file.
I'm getting errors like this:
./scriptas: line 2: syntax error near unexpected token `head'
./scriptas: line 2: `head -n 1 $file | while read folder'
And my second question: how do I add a second variable from command line (putty) $directory ?
Example i have file with text:
one two three
five seven nine eleven
okey
i need script to take the first line and create directories "one" "two" "three"
You have to put do before the command in a for/while cycle.
Your code should look like something like this:
#!/bin/bash
files=$*
for file in $files
do
head -n1 "$file" | while read dname
do
mkdir $dname
done
done
as for other variables, the simple syntax is a number behind the $ sign.
so you could do
files="$1"
directory="$2"
and then run the script as
./script.sh "file1.txt file2.txt file3.txt" dir2
More complex solutions include getopts and such....
Updated the script. You can use it in this way:
script.sh "one.txt two.txt three.txt" destdir
#! /bin/bash
for files in $1
do
for i in $(head -n 1 $files)
do
if [ -z $2 ]
then
mkdir $i
else
mkdir $2/$i -p
fi
done
done

Bash Script Variable

#!/bin/bash
RESULT=$(grep -i -e "\.[a-zA-z]\{3\}$" ./test.txt)
for i in $(RESULT);
do
echo "$i"
FILENAME="$(dirname $RESULT)"
done
I have a problem with the line FILENAME="$(dirname $RESULT)". Running the script in debugging mode(bash -x script-name), the ouput is:
test.sh: line 9: RESULT: command not found
For some reason, it can't take the result of the variable RESULT and save the output of dir command to the new variable FILENAME. I can't understand why this happens.
After lots of tries, I found the solution to save full path of finame and finame to two different variables.
Now, I want for each finame, find non-case sensitive of each filename. For example, looking for file image.png, it doesn't matter if the file is image.PNG
I am running the script
while read -r name; do
echo "$name"
FILENAME="$(dirname $name)"
BASENAME="$(basename $name)"
done < <(grep -i -e "\.[a-zA-z]\{3\}$" ./test.txt)
and then enter the command:
find . $FILENAME -iname $BASENAME
but it says command FILENAME and BASENAME not found.
The syntax:
$(RESULT)
denotes command substitution. Saying so would attempt to run the command RESULT.
In order to substitute the result of the variable RESULT, say:
${RESULT}
instead.
Moreover, if the command returns more than one line of output this approach wouldn't work.
Instead say:
while read -r name; do
echo "$name"
FILENAME="$(dirname $name)"
done < <(grep -i -e "\.[a-zA-z]\{3\}$" ./test.txt)
The <(command) syntax is referred to as Process Substitution.
for i in $(RESULT) isn't right.You can use $RESULT or ${RESULT}

save wild-card in variable in shell script and evaluate/expand them at runtime

I am having trouble running the script below (in Cygwin on win 7 mind you).
Lets call it "myscript.sh"
When I run it, the following is what I input:
yearmonth: 2011-03
daypattern: 2{5,6,7}
logfilename: error*
query: WARN
#! /bin/bash
yearmonth=''
daypattern=''
logfilename=''
sPath=''
q=''
echo -n "yearmonth: "
read yearmonth
echo -n "daypattern: "
read daypattern
echo -n "logfilename: "
read logfilename
echo -n "query: "
read q
cat "$yearmonth/$daypattern/$logfilename" | grep --color $q
The output I get is:
cat: /2011-03/2{5,6,7}/error* No such
directory of file exists.
However, if I enter daypattern=25 OR daypattern=26 etc. the script will work.
Also, of course if I type the command in the shell itself, the wildcards are expanded as expected.
But this is not what I want.
I want to be able to PROMPT the user to enter the expressions as they need, and then later, in the script, execute these commands.
Any ideas how this can be possible?
Your help is much appreciated.
Try eval, this should work for the {a,d} and * cases
eval grep --color $q ${yearmonth}/${daypattern}/${logfilename}
Use quote to prevent wildcard expansion:
$ a="*.py"
$ echo $a
google.py pair.py recipe-523047-1.py
$ echo "$a"
*.py

How to process file names with variables from a list in a file in Bash

I have a file "FileList.txt" with this text:
/home/myusername/file1.txt
~/file2.txt
${HOME}/file3.txt
All 3 files exist in my home directory. I want to process each file in the list from a bash script. Here is a simplified example:
LIST=`cat FileList.txt`
for file in $LIST
do
echo $file
ls $file
done
When I run the script, I get this output:
/home/myusername/file1.txt
/home/myusername/file1.txt
~/file2.txt
ls: ~/file2.txt: No such file or directory
${HOME}/file3.txt
ls: ${HOME}/file3.txt: No such file or directory
As you can see, file1.txt works fine. But the other 2 files do not work. I think it is because the "${HOME}" variable does not get resolved to "/home/myusername/". I have tried lots of things with no success, does anyone know how to fix this?
Thanks,
-Ben
Use eval:
while read file ; do
eval echo $file
eval ls $file
done < FileList.txt
From the bash manpage regarding the eval command:
The args are read and concatenated together into a single command. This command is
then read and executed by the shell, and its exit status is returned as the value of
eval. If there are no args, or only null arguments, eval returns 0.
you will hit "spaces problem" using the for loop with cat. Manipulate IFS, or use a while read loop instead
while read -r line; do eval ls "$line"; done < file
Change "ls $file" to "eval ls $file" to get the shell to do its expansion.

Resources