I am trying to script a procedure but I am really stuck now.
In a folder, I have some files, let say:
000001.dat
000002.dat
000003.dat
000004.dat
000005.dat
000006.dat
000007.dat
000008.dat
000009.dat
000010.dat
In a variable, I have echo $num > 000009.
What I would like to do is to suppress the intermediate file like:
rm -f {000001..${num}}*, but it doesn't work...
If I use rm -f {000001..000009}*, it works! So I think it is a problem when reading the num variable.
Any helps? :)
Thank you in advance!
One way using eval:
$ x=1;y=9
$ echo {$x..$y}
{1..9}
$ eval echo {$x..$y}
1 2 3 4 5 6 7 8 9
Related
I'm trying to make directories using a variable in the directory name from a variables in an array, but it doesn't seem to concatenate the streams like I thought they would. I've tried a couple different ways.
I'm trying to get three directories named:
test_6_bash_with_directory, test_8_bash_with_directory, test_10_bash_with_directory
variable=`seq 6 2 10`
for i in "${variable[#]}"
do
:
directory_name="./test_${i}_bash_with_directory"
mkdir $directory_name
echo $i
done
This gives me three directories test_6, 8 and 10_bash_with_directory. Replacing ${i} with ${variable} has the same result.
I'd also tried having the mkdir call in the same line as the directory concatenation:
mkdir "./test_${i}_bash_with_directory"
and I got one directory called test_6?8?10_bash_with_directory
So, how do I write this correctly? Thank you for replies!
Your problem is that variable is a string, not an array. You want:
variable=(`seq 6 2 10`)
for i in "${variable[#]}"
do
directory_name="./test_${i}_bash_with_directory"
mkdir $directory_name
echo $i
done
Note the (...) around your sequence of values.
This problem is a homework, I know there would be much easier ways of solving this problem, but it is what it is.
The question goes as follows:
-I have a bash script that does some creates some files.
-I have to pass this first argument of this script ( which is a directory ) to another script trough a pipeline ( | ).
The problem comes in when I do try and pass this directory as an argument, in the other script, the argument I receive is null.
This is the whole code, in this exact order.
Nothing was left out.
The first script receives at least 11 argument:
if [[ $# -lt 11 ]]; then
echo "Not enough arguments." >&2;
exit 1;
fi;
The script will check if the first argument is an actual directory:
if [[ ! -d $1 ]]; then
echo "Not a valid first argument." >&2;
exit 1;
fi;
Here, I'll save my first directory here so that I can shift, and then I'm going to declare more stuff that i need
Directory=$1;
shift;
N=$#
name_array=("$#")
Pos=0;
Afterwards, the script will use all the other arguments to create .txt files with those names, and add a number of non-null lines in each .txt file ( So, argument2.txt has N-1 lines, argument3.txt has N-2 lines ... argumentN.txt has 1 line.) Afterwards, I have to change their permissions to 600.
while [[ $# -gt 0 ]]; do
if [[ -a "$Directory"/"$1".txt ]]; then
rm "$Directory"/"$1".txt;
fi
touch "$Directory"/"$1".txt
for((i=0;i<N;i++)); do
echo "$N" >> "$Directory"/"$1".txt;
done;
chmod u=rw "$Directory"/"$1".txt;
N=$(($N-1));
name_array["$Pos"]="$Directory"/"$1".txt;
Pos=$(($Pos + 1));
shift;
done;
Problem comes here, I'm trying to echo the first directory..
echo $Directory;
I have tried this as well, with the same results as the one above
echo "$(cd "$(dirname "$Directory")" && pwd -P)/$(basename "$Directory")";
.. like this so I can use in the Shell the pipeline commands.
The second script will receive the directory, enter it and search trough all the files that have been created just now.
In the Unix terminal, I use this:
./FirstScript.bash 1 2 3 4 5 6 7 8 9 10 11 12 | ./SecondScript.bash
Thank you in advance!
Thanx for being honest, and of course we're not going to do your homework, but,...
Most of the code seems pretty good. There are some smaller issues, which you might easily solve with shellcheck (if it isn't installed, install it or use the web version), and I would not put ; at the end of each line.
So, instead of running the complete pipeline at once, break it down to find where your problem lies. If you run
./FirstScript.bash 1 2 3 4 5 6 7 8 9 10 11 12
If the output is as expected (so, with the echo $Directory), and the files are created, then the first script is good. So, in this case, the directory 1 will contain the files 2 3 4 5 6 7 8 9 10 11 12, and the output will be 1.
Then, you will run the second script
./SecondScript.bash
and as input you will give:
1
^D
(that is control-d on Unix). And then the second script should do what you want (or not).
In this way you can debug the scripts separately.
(quick face-palm question: is 1 really the directory you want, or did you just forget the directory name as first argument?)
this works:
sort <(seq 10)
but this does not work
sort <(seq.sh 10)
where seq.sh looks like
#/bin/bash
seq $1
How I can make seq.sh work for this?
-- edit --
sorry for typo.
seq.sh is excutable and has correct shabang line.
I guess it is related with EOF something.
This works as well with trailing &
sort <(./seq.sh 10 &)
It works if you use seq.sh as a path, for example ./seq.sh or its absolute path. Remember to make it executable.
You may need to add the ! to the shebang.
#!/bin/bash
Also I would make sure that the shell script is executable.
chmod +x seq.sh
lastly, pipe into sort: (the example has an input of 10)
./seq.sh 10 | sort
This was my output:
user#MBP:~/Desktop$ ./seq.sh 10 | sort
1
10
2
3
4
5
6
7
8
9
so the thing is, I'm trying to code a shell script that creates multiple image files in an ascending order, but, the ones with only one digit must come with a zero first. I'm a beginner and searching throughout the internet I've found that there are some syntax differences when it comes to the indexing system, so on my computer the following "for" syntax works fine, but I'm sure there's a better approach to that. there it goes:
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do
if (${i:0:1} == "0") then
touch "0${i}.jpg"
else
touch "$i.jpg"
fi
done
it returns "bad substitution". is there anything wrong with this approach?
for i in {0..15}; do printf -v name "%02i.jpg" $i; touch "$name" ; done
Or, if it is easier to read:
for i in {0..15}; do
printf -v name "%02i.jpg" $i
touch "$name"
done
When this is done, the following files are created:
$ ls
00.jpg 01.jpg 02.jpg 03.jpg 04.jpg 05.jpg 06.jpg 07.jpg 08.jpg 09.jpg 10.jpg 11.jpg 12.jpg 13.jpg 14.jpg 15.jpg
Explanation
for i in {0..15}; do
This starts the loop.
printf -v name "%02i.jpg" $i
This creates a shell variable name which has the desired format. %02i instructs printf to write the number out in two space with zero-padding.
touch "$name"
This creates the file
done
This signals the end of the loop.
Alternative
Starting from the script in the question, a couple changes are needed on the if statement. The following works:
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do
if [ "$i" -le 9 ]; then
touch "0${i}.jpg"
else
touch "$i.jpg"
fi
done
This question already has answers here:
Dynamic variable names in Bash
(19 answers)
Closed 6 years ago.
I apologise for the pretty terrible title - and the poor quality post - but what I basically want to do is this:
for I in 1 2 3 4
echo $VAR$I # echo the contents of $VAR1, $VAR2, $VAR3, etc.
Obviously the above does not work - it will (I think) try and echo the variable called $VAR$I Is this possible in Bash?
Yes, but don't do that. Use an array instead.
If you still insist on doing it that way...
$ foo1=123
$ bar=foo1
$ echo "${!bar}"
123
for I in 1 2 3 4 5; do
TMP="VAR$I"
echo ${!TMP}
done
I have a general rule that if I need indirect access to variables (ditto arrays), then it is time to convert the script from shell into Perl/Python/etc. Advanced coding in shell though possible quickly becomes a mess.
You should think about using bash arrays for this sort of work:
pax> set arr=(9 8 7 6)
pax> set idx=2
pax> echo ${arr[!idx]}
7
For the case where you don't want to refactor your variables into arrays...
One way...
$ for I in 1 2 3 4; do TEMP=VAR$I ; echo ${!TEMP} ; done
Another way...
$ for I in 1 2 3 4; do eval echo \$$(eval echo VAR$I) ; done
I haven't found a simpler way that works. For example, this does not work...
$ for I in 1 2 3 4; do echo ${!VAR$I} ; done
bash: ${!VAR$I}: bad substitution
for I in {1..5}; do
echo $((VAR$I))
done
Yes. See Advanced Bash-Scripting Guide
This definately looks like an array type of situation. Here's a link that has a very nice discussion (with many examples) of how to use arrays in bash: Arrays