2

Я пишу сценарий, который применяет команду для загрузки файлов. То, как я это автоматизирую, сводится к

#!/bin bash
for in_file in ${PWD}/*/*/*.txt; do
    out_file="${in_file//in/out}"
    CM="/usr/local/bin/command -in \"${in_file}\" -out \"${out_file}\""
    echo ${CM}
    ${CM}
done

Типичный вывод, который я получаю,

/usr/local/bin/command -in "/home/user/infile.txt" -out "/home/user/outfile.txt"
error:
/usr/local/bin/command: unable to find file "/home/user/infile.txt"
...

Но затем я вырезал и вставил в командную строку ту же команду, дословно, включая все кавычки и т.д., И она запускается без проблем!

Потому что много имен файлов (что я не сделал!) есть пробелы, мне нужны цитаты в сценарии. Но может кто-нибудь сказать мне, почему они не работают в сценарии и работают в командной строке? И есть ли способ сделать это правильно?

2 ответа2

4

Используйте массив: это лучший способ сохранить команду из нескольких слов с аргументами, содержащими пробелы.

#!/bin bash
for in_file in ${PWD}/*/*/*.txt; do
    out_file="${in_file//in/out}"
    cmd=( /usr/local/bin/command -in "$in_file" -out "$out_file" )
    echo "${cmd[@]}"
    "${cmd[@]}"
done
1

«$ {CM}» не будет использовать пустые символы в качестве разделителей. Таким образом, bash считает, что вся строка - это имя вашей программы.

С $ {CM} bash думаю, что "являются частью аргумента.

Вы можете использовать << eval "$ {CM}" >>, но у вас могут быть побочные эффекты с неэкранированными специальными символами в именах файлов.

Так что лучше следующее:

Это работает ?

#!/bin bash
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out"
    CM="/usr/local/bin/command -in \"$in_file\" -out \"$out_file\""
    echo "${CM}"
    /usr/local/bin/command -in "$in_file" -out "$out_file"
done

Вместо того, чтобы выводить ваши команды, используйте «set -x» для отладки вашего скрипта:

#!/bin bash
set -x
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out" 
    /usr/local/bin/command -in "$in_file" -out "$out_file"
done

или это :

#!/bin bash
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out" 
    set -x
    /usr/local/bin/command -in "$in_file" -out "$out_file"
    set +x
done

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .