#bash #shell #xargs
Вопрос:
Я пытаюсь написать короткий сценарий и следующую команду:
echo "aaa111 bbb111" | xargs -I {} echo {} | sed 's/111/222/g'
возвращается aaa222 bbb222
, чего я и ожидаю.
Я ожидал следующей команды:
echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')
вернуть то же самое, но оно возвращается aaa111 bbb111
! Это почему?
UPD: Чего я пытаюсь достичь:
У меня много файлов, таких как pic30-coff-gcc
, pic30-coff-ag
, и т. Д., И мне нужно создать символическую ссылку для каждого файла, например pic30-gcc
— gt; gt; pic30-coff-gcc
и т. Д.
Поэтому я написал это:
ls|grep 'coff-'|xargs -I {} ln -s {} $(echo {} | sed 's/coff-//g')
Это не работает: для каждого файла он сообщает, что файл существует. Я проверил команду следующим образом:
ls|grep 'coff-'|xargs -I {} echo "ln -s {} $(echo {} | sed 's/coff-//g')"
И да, эта sed
часть не работает:
ln -s pic30-coff-gcc pic30-coff-gcc ln -s pic30-coff-gcc-4.0.3 pic30-coff-gcc-4.0.3 ...
Но если я просто наберу
echo "ln -s pic30-coff-gcc $(echo pic30-coff-gcc | sed 's/coff-//g')"
это работает:
ln -s pic30-coff-gcc pic30-gcc
Затем я написал тестовую команду aaa111
, и она тоже не работает. До сих пор не могу понять, почему.
Ответ №1:
for
Ответ на цикл — это именно то, что я пришел сюда не для того, чтобы читать. Вся цель xargs
состоит в том, чтобы избежать этого цикла. xargs
возможно, это не самый умный инструмент для данного конкретного случая, но вопрос был в этом.
Вот решение, к которому я пришел. Возможно, это не идеально, но тем не менее работает :
echo "aaa111 bbb111" | xargs -I {} sh -c "echo $(echo {} | sed 's/111/222/g')" # Outputs aaa222 bbb222
Вы можете придумать разные варианты одной и той же команды :
echo "aaa111 bbb111" | xargs -I {} sh -c 'echo $(echo {} | sed "s/111/222/g")' echo "aaa111 bbb111" | xargs -I {} sh -c "echo `echo {} | sed 's/111/222/g'`"
Главное здесь-просто вызвать новую оболочку, которая выполнит замену команды после xargs
того, как заменит replace-str
(здесь {}
) правильным содержимым.
Комментарии:
1. Лучшей формулировкой было бы
echo "aaa111 bbb111" | xargs -I @@ bash -c 'temp="@@"; echo ${temp//111/222}'
2. Хотя это и правильно, цель здесь состояла в том, чтобы использовать ту же команду, что и в OP.
Ответ №2:
$(echo {} | sed 's/111/222/g')
оценивается до того, как он будет передан в xargs
качестве параметра. Оно вернется {}
.
Следовательно:
echo "aaa111 bbb111" | xargs -I {} echo $(echo {} | sed 's/111/222/g')
это то же самое, что
echo "aaa111 bbb111" | xargs -I {} echo {}
Ответ №3:
Кажется, что все, что вам нужно, — это простой цикл:
for file in *coff*; do ln -s "${file}" "${file/coff-/}" done
Ответ №4:
Вот еще один вариант, который изменяет каждую входную строку для печати источника и назначения, а затем заставляет xargs
читать два аргумента одновременно.
# aside: avoid ls | grep printf '%sn' coff-* | sed 's/(coff-(.*))/1 2/' | xargs -n 2 ln -s
Это, очевидно, хрупко; если у вас есть имена файлов, имена которых содержат пробелы, они будут неправильно проанализированы.