bash: passing params from $3 onwards to another program (say tar) - bash

let's say my script takes filenames starting from $3
e.g.
archive u 2342 a.txt b.png c.html d.js
archive u 2222 a.txt b.png
I want to zip all the files listed starting from $3
How can I do that?
thanks

zip archivename.zip "${#:3}"

The bash command shift is your friend.
The script example.sh
#!/bin/bash
shift 3
echo $*
called with example.sh 1 2 3 4 5 will output 4 5.

FIRST=$1
shift
SECOND=$1
shift
echo $FIRST
echo $SECOND
echo tar cf archive.tar "$#"
Input:
./test.sh 1 2 3 4 5
Output:
1
2
tar cf archive.tar 3 4 5

Related

Bash check if file1 line is partly contained in a line from file2

I have have a file1 with ids and a file2 that is a list with full names of all files in a folder.
Ids from file1 look like this P001A, P001I, P002A, P002I ...
And the names of the files from file2 contain those ids in themselves. I want to create a new file3 that contains all full names from file2 that have the ids from file1.
File2 has like 100k lines, while file1 has 89 so there are many lines from file2 that contain the same id from a line in file1.
This is the script that I am using, but it says
FILE1: command not found FILE2: command not found
-bash: ${FILE1}: ambiguous redirect
1#!/bin/sh
2 FILE1 ="$1"
3 FILE2 ="$2"
4 while read -r value1
5 do
6 while read -r value2
7 do
8 if [[ "$value1" == *"$value2"* ]]
9 then
10 echo $value2
11 fi
12 done <${FILE2}
13 done <${FILE1} > file3.list
What is wrong here? And do you know if that script is supposed to be like that or I should make some other way.
as #Benjamin said - you use /bin/sh but use "[[" and "]]" to test.
I rewrote your code to use /bin/sh:
#!/bin/sh
is_substring(){
case "$2" in
*$1*) return 0;;
*) return 1;;
esac
}
FILE1="$1"
FILE2="$2"
while read -r value1
do
while read -r value2
do
if is_substring "$value1" "$value2"
then
echo $value2
fi
done <${FILE2}
done <${FILE1} > file3.list
for bash:
#!/bin/bash
FILE1="$1"
FILE2="$2"
(while read -r value1
do
(while read -r value2
do
if [[ -z "${value2##*$value1*}" ]]
then
echo $value2
fi
done) < ${FILE2}
done <${FILE1}) > file3.list
I solved my problem with this script
1#!/bin/bash
2 for i in $(cat file1);
3 do
4 FILENAME=$(find /directory/ -regextype posix-egrep -regex ".*/20170001${i}[0-9]*\.wav")
5 echo "${FILENAME}";
6 done > file3
I didn't even need the file with the file names.

how to group all arguments as position argument for `xargs`

I have a script which takes in only one positional parameter which is a list of values, and I'm trying to get the parameter from stdin with xargs.
However by default, xargs passes all the lists to my script as positional parameters, e.g. when doing:
echo 1 2 3 | xargs myScript, it will essentially be myScript 1 2 3, and what I'm looking for is myScript "1 2 3". What is the best way to achieve this?
Change the delimiter.
$ echo 1 2 3 | xargs -d '\n' printf '%s\n'
1 2 3
Not all xargs implementations have -d though.
And not sure if there is an actual use case for this but you can also resort to spawning another shell instance if you have to. Like
$ echo -e '1 2\n3' | xargs sh -c 'printf '\''%s\n'\'' "$*"' sh
1 2 3
If the input can be altered, you can do this. But not sure if this is what you wanted.
echo \"1 2 3\"|xargs ./myScript
Here is the example.
$ cat myScript
#!/bin/bash
echo $1; shift
echo $1; shift
echo $1;
$ echo \"1 2 3\"|xargs ./myScript
1 2 3
$ echo 1 2 3|xargs ./myScript
1
2
3

Pass arguments to a script that is an argument to a different script

I am new to programming, so plz bear with the way I try to explain my problem (also any help regarding how to elegantly phrase the tile is welcome).
I have a bash script (say for example script1.sh ) that takes in arguments a, b and c(another script). Essentially, argument c for script1.sh is the name of another script (let's say script2.sh). However, script2.sh takes in arguments d,e and f. So my question is, how do I pass arguments to script1.sh ?? (example, ./script1.sh -a 1 -b 2 -c script2.sh -d 3 -e 4 -f 5)
Sorry in advance if the above does not make sense, not sure how else to phrase it...
You should use "" for that
./script1.sh -a 1 -b 2 -c "script2.sh -d 3 -e 4 -f 5"
Try script1.sh with this code
#!/bin/bash
for arg in "$#"; { # loop through all arguments passed to the script
echo $arg
}
The output will be
$ ./script1.sh -a 1 -b 2 -c "script2.sh -d 3 -e 4 -f 5"
-a
1
-b
2
-c
script2.sh -d 3 -e 4 -f 5
But if you run this
#!/bin/bash
for arg in $#; { # no double quotes around $#
echo $arg
}
The output will be
$ ./script1.sh -a 1 -b 2 -c "script2.sh -d 3 -e 4 -f 5"
-a
1
-b
2
-c
script2.sh
-d
3
4
-f
5
But there is no -e why? Coz echo supports argument -e and use it.

How to use shell keyword "select" to get parameters by pipeline?

My script v.sh
select f in "$#" ; do
echo $f
done
v.sh 1 2 3 I can select options after the command executed.
echo 1 2 3 | v.sh Showing nothing.
echo 1 2 3 | xargs v.sh Showing the options, but I can't select them.
How to select the options? Thx in advance.
With bash:
#!/bin/bash
if [[ -z $1 ]]; then
# no arguments, read from stdin
mapfile -t input </dev/stdin
exec </dev/tty
else
# use arguments
input=("$#")
fi
select f in "${input[#]}" ; do
echo "$f"
done
Example with stdin:
cut -d : -f 1 /etc/passwd | ./script.sh
with arguments:
./script.sh 1 2 "3 3" 4 5

Bash, argument list segment

If you have a list in python, and you want the elements from 2 to n can do something nice like
list[2:]
I'd like to something similar with argv in Bash. I want to pass all the elements from $2 to argc to a command. I currently have
command $2 $3 $4 $5 $6 $7 $8 $9
but this is less than elegant. Would would be the "proper" way?
you can do "slicing" as well, $# gets all the arguments in bash.
echo "${#:2}"
gets 2nd argument onwards
eg
$ cat shell.sh
#!/bin/bash
echo "${#:2}"
$ ./shell.sh 1 2 3 4
2 3 4
Store $1 somewhere, then shift and use $#?
script1.sh:
#!/bin/bash
echo "$#"
script2.sh:
#!/bin/bash
shift
echo "$#"
$ sh script1.sh 1 2 3 4
1 2 3 4
$ sh script2.sh 1 2 3 4
2 3 4

Resources