Можно ли использовать вывод канала в качестве аргумента сценария оболочки?

Предположим, у меня есть скрипт оболочки bash с именем Myscript.sh что нужен один аргумент в качестве входных данных.

Но я хочу, чтобы содержимое текстового файла называлось text.txt быть этим аргументом.

Я пробовал это, но это не работает:

cat text.txt | ./Myscript.sh

Есть ли способ сделать это?

10 ответов

Решение

Подстановка команд.

./Myscript.sh "$(cat text.txt)"

Вы можете использовать вывод канала в качестве аргумента сценария оболочки.

Попробуйте этот метод:

cat text.txt | xargs -I {} ./Myscript.sh {}

Чтобы завершить @bac0n, который, по моему мнению, единственный, кто правильно отвечает на вопрос, вот короткий лайнер, который добавит переданные по конвейеру аргументы в список аргументов вашего скрипта:

      #!/bin/bash

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

echo "$@"

Пример использования:

      $ ./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

Направьте это вxargsперед фактической командой, напримерcat text.txt | xargs ./Myscript.sh

Если в файле более одной команды, рассмотрите возможность использования xargs или параллельного кода, например

xargs -d '\n' Myscript.sh < text.txt
parallel -j4 Myscript.sh < text.txt

Читая stdin с mapfile, вы можете переустановить позиционные параметры.

#!/bin/bash

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

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

(Цитата "$@" сделает for линии цикла вместо).

$ cat test.txt | ./script.sh
1 one
2 two
3 tree

Этот вопрос немного устарел, но я нашел это решение наиболее простым для понимания и хотел поделиться им.

Если вы хотите принять содержимоеtest.txtв качестве входных данных для вашего сценария (например,cat test.txt | ./myEchoScript), вы можете сделать следующее, чтобы прочитать из стандартного ввода

      if [ -p /dev/stdin ]; then
        input=$(cat)
else
        echo "expecting input to be piped in, exiting script"
        exit
fi
echo $input

Затем запустить:

      $ echo "testing testing" > test.txt
$ cat test.txt | ./myEchoScript.sh 
testing testing

Пытаться,

 $ 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

так что вы можете ввести значения по одному, чтобы comli.sh от comli.txt,

Если в файле есть символы новой строки (LF) или табуляции, и вы хотите фактически поместить их в один аргумент (не заставлять bash конвертировать LF в пробелы и использовать каждое слово в качестве отдельного аргумента), вы можете использовать это:

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

(используется подоболочка, поэтому IFS не затрагивается в основной оболочке)

Простой тест, показывающий, что это работает:

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

Версия без оболочки:

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

См. также: https://stackoverflow.com/questions/2789319/file-content-into-unix-variable-with-newlines

Процесс замены

./Myscript.sh <(cat text.txt)

Смотрите, например, https://www.gnu.org/software/bash/manual/bash.html

Другие вопросы по тегам