56

Suppose I have a bash shell script called Myscript.sh that need one argument as input.

But I want the content of the text file called text.txt to be that argument.

I have tried this but it does not work:

cat text.txt | ./Myscript.sh

Is there a way to do this?

7ochem
  • 161
  • 2
  • 11
Narin
  • 663
  • 1
  • 5
  • 4

8 Answers8

55

You can use pipe output as a shell script argument.

Try this method:

cat text.txt | xargs -I {} ./Myscript.sh {}
mic84
  • 2,373
  • 2
  • 21
  • 17
zzart
  • 651
  • 5
  • 3
41

Command substitution.

./Myscript.sh "$(cat text.txt)"
Ignacio Vazquez-Abrams
  • 107,382
  • 8
  • 188
  • 239
  • 2
    This works, but if `cat` fails, then `Myscript.sh` will still execute. Piping with xargs ensures that the execution stops. – M.Vanderlee May 07 '20 at 14:07
5

To complete @bac0n which IMHO is the only one to correctly answers the question, here is a short-liner which will prepend piped arguments to your script arguments list :

#!/bin/bash

declare -a A=("$@")
[[ -p /dev/stdin ]] && { \
    mapfile -t -O ${#A[@]} A; set -- "${A[@]}"; \
}

echo "$@"

Example use :

$ ./script.sh arg1 arg2 arg3
> arg1 arg2 arg3

$ echo "piped1 piped2 piped3" | ./script.sh
> piped1 piped2 piped3

$ echo "piped1 piped2 piped3" | ./script.sh arg1 arg2 arg3
> piped1 piped2 piped3 arg1 arg2 arg3

bac0n
  • 123
  • 5
aznoqmous
  • 51
  • 1
  • 3
  • `mapfile` reads **lines** from stdin as default if you want to change this behavior, e.g., if you like to split on words, you have to specify a delimiter. – bac0n Dec 24 '20 at 12:22
4

If you have more than one set of arguments in the file (for multiple calls), consider using xargs or parallel, e.g.

xargs -d '\n' Myscript.sh < text.txt
parallel -j4 Myscript.sh < text.txt
reinierpost
  • 2,122
  • 1
  • 17
  • 22
1

By reading stdin with mapfile you can re-set the positional parameters.

#!/bin/bash

[[ -p /dev/stdin ]] && { mapfile -t; set -- "${MAPFILE[@]}"; }

for i in "$@"; do
    echo "$((++n)) $i"
done

$ cat test.txt | ./script.sh
1 first
2 second line 
3 third
bac0n
  • 123
  • 5
0

If there are newlines (LF) or tabs in the file and you want to actually put them in one single argument (not have bash convert LF to spaces and use each word as a separate argument), you can use this:

./Myscript.sh "$(IFS=''; cat text.txt)"

(subshell used so IFS is untouched in main shell)

Simple test to show it works:

echo ">>>$(IFS=''; cat text.txt)<<<"

Non-sub-shell version:

IFS=" " ; echo ">>>$(cat text.txt)<<<" ; IFS=$' \t\n'

See also: https://stackoverflow.com/questions/2789319/file-content-into-unix-variable-with-newlines

0

Pipe it into xargs before the actual command, like cat text.txt | xargs ./Myscript.sh

0

Try,

 $ cat comli.txt
 date
 who
 screen
 wget

 $ cat comli.sh
 #!/bin/bash
 which $1

 $ for i in `cat comli.txt` ; do ./comli.sh $i ; done

so you can enter the values one by one to comli.sh from comli.txt.

7ochem
  • 161
  • 2
  • 11
Ranjithkumar T
  • 449
  • 1
  • 5
  • 6