Найдите полный путь и имя файла в каталоге, затем перейдите к исполняемый файл в качестве аргументов

Это будет истинно, если $ PID1 запущен: if [kill -s 0 $ PID1]

У вас может быть несколько предложений if. Они будут оценивать как ложь, если PID не работает. Этот пункт (в сочетании с другими) должен управлять потоком сценария по вашему желанию.

5
23.05.2017, 15:39
5 ответов

При работе с xargs вы всегда должны тестировать свои решения с вводом, начинающимся с «-» и содержащим двойной пробел, и «потому что xargs печально известен тем, что имеет дело плохо с ними:

mkdir -- '-"  '"'"
seq 10 > ./-\"\ \ \'/'-"  '"'".txt

Вот решение, использующее GNU Parallel:

find . -name "*.txt" -print0 |parallel  -0 ./thulac '<' {} '>' {/}

<и> необходимо заключить в кавычки, поскольку в противном случае они будут интерпретироваться оболочкой, которая запускает параллельно . Мы хотим, чтобы они вместо этого интерпретироваться оболочкой, запущенной parallel .

2
27.01.2020, 20:36

Проблема с вашей командой поиска.
Чтобы разделить два имени, добавьте пробел в формате printf

find /mnt/test -name "*.txt"  -print0 -printf " %f\n"
                                               ^ ( note the space above)
1
27.01.2020, 20:36
find /mnt/test -name "*.txt" -print0 -printf "%f\0" |
xargs -0 -n 2 bash -c 'shift $1; ./thulac < $1 > /mnt/tokenized/$2' 2 1

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

В противном случае произойдет то, что полное имя пути к одному файлу будет объединено с базовым именем следующего файла, явление, которое вы наблюдали в случае нескольких имен файлов!

И затем вам нужно передать 2 аргумента за раз bash alligator , иначе он будет потреблять столько аргументов, сколько ему разрешено, но он передает вашему исполняемому файлу только первые два ./thulac .

Лучшая альтернатива - отказаться от xargs и выполнять всю свою работу в find , поскольку как таковая xargs работает с двумя аргументами за раз, что устраняет любые преимущества xargs . В этой версии мы предоставляем полный путь к bash и вычисляем имя файла самим bash , а не полагаемся на find для выполнения Это.

find /mnt/test -name "*.txt" -exec bash -c './thulac < "$1" \
  > "/mnt/tokenized/${1##*/}"' {} {} \;

Причина проблемы

1. Good case when only 1 file present
-print0  -printf '%f'

 /mnt/test/test.txt\0test.txt
 |-----------------|--------|

arg0 = /mnt/test/test.txt
arg1 = test.txt
bash -c 'thulac < $0 > /mnt/tokenized/$1'
thulac < /mnt/test/test.txt > /mnt/tokenized/test.txt

2. Error case when > 1 file present
-print0  -printf '%f'
/mnt/test/test.txt\0test.txt/mnt/test/test33.txt\0test33.txt
|-----------------|-----------------------------|----------|

arg0 = /mnt/test/test.txt
arg1 = test.txt/mnt/test/test33.txt
arg2 = test33.txt
bash -c 'thulac < $0 > /mnt/tokenized/$1'
thulac < /mnt/test/test.txt > /mnt/tokenized/test.txt/mnt/test/test33.txt

Исправить

We saw that the mixup occurred due to the absence of the delimiter '\0' in the -printf "%f"
So the correct way is:
find ... -print0 -printf "%f\0" | xargs ...
Ensuring that the list is partitioned at the right places and the 
sequence of fullpath1+file1\0fullpath2+file2\0... is maintained.

Now coming to the 'xargs' part, we write:
xargs -0 -n 2 bash -c '...' 2 1

Points to observe are the following:
   a) '-0' => arguments to xargs will be taken to be NULL separated.
   b) -n 2 => we feed 2 args at a time to bash from the total pool 
      delivered to xargs by find.
   c) 2 1 is just a best practice to get over different shell's behavior
      regarding what construes as $0, $1, $2, ...; In your particular case since you
      already know that $0 -> first arg, $1 -> 2nd arg, we could just as well have
     written what you did:
    find ... | xargs -0 -n 2 bash -c './thulac < $0 > /mnt/tokenized/$1'
2
27.01.2020, 20:36
find /tmp/test -name '*.txt' \
 -exec bash -c './thulac < "$(readlink -f {})" > "/mnt/tokenized/$(basename {})"' \;

Используйте поиск для поиска файлов и выполнения команд над результатами. С помощью bash -c 'command' вы можете выполнить несколько $ ().

Используйте readlink -f {} , чтобы создать полный путь к результату.

Используйте базовое имя {} , чтобы удалить путь из результата.

2
27.01.2020, 20:36

Вы не говорите точно, чего должен достичь ваш сценарий, но если вы хотите передать каждый нечетный файл в качестве первого аргумента и каждое четное имя файла в качестве второго аргумента, вот как это сделать переносимым способом:

t=$(mktemp)
find /tmp/test -name "*.txt" -exec sh -c '
    if [ -s $1 ]
    then
        ./thulac < "$(<$1)" > "/mnt/tokenized/$2"
    else
        printf "%s" "$2" > "$1"
    fi' sh $t {} \;
rm $t

Если вы просто хочу передать путь и имя файла каждого найденного файла, ответ проще, по-прежнему только с использованием переносимых команд и синтаксиса (POSIX), то есть не зависит от bash, GNU find и GNU xargs:

find /tmp/test -name "*.txt" -exec sh -c '
    ./thulac < "$1" > "/mnt/tokenized/$(basename "$1")"' sh {} \;

Обратите внимание, что { } нужно заключать в кавычки только при использовании оболочки fish, что очень маловероятно.

1
27.01.2020, 20:36

Теги

Похожие вопросы