Экранирование вложенных двойных -кавычек в поврежденном CSV-файле

После запуска mdfind... | xargs cp...код ошибки в $?совпадает с кодом xargs, так как это последняя команда в конвейере. xargsвозвращает 123, если какая-либо команда, которую он выполнил, не удалась, но если mdfindне производит никакого вывода, то xargsничего не делает, поэтому он также не завершается ошибкой.

Однако в Bash коды выхода всех команд в последнем конвейере можно найти в переменной массива PIPESTATUS. Код выхода первой команды ${PIPESTATUS[0]}и т. д.

$ false | true | xargs false
$ echo "${PIPESTATUS[*]}"
1 0 123

Таким образом, вместо использования $?, которое дает вам статус выхода xargs, вы можете использовать ${PIPESTATUS[0]}, что дает вам статус выхода mdfind. Или сохраните лот в другую переменную и протестируйте обе.(saved=("${PIPESTATUS[@]}"))

В качестве альтернативы используйте set -o pipefail, чтобы $?давал вам код выхода последней неудачной команды конвейера, если какая-либо из них не работает.(false | trueприведет к $?=1.)

0
11.09.2020, 19:15
1 ответ

Я создал образец входного файла, в котором каждая строка состоит из 10 полей с полями 4 и 9, возможно, заключенными в кавычки:

$ cat file
n9sih438,4994fa72322,PMC,here is an unquoted string,10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,here is an unquoted string,2007-07-25
n9sih438,4994fa72322,PMC,"here is a,",string,","within,", quotes.",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,here is an unquoted string,2007-07-25
n9sih438,4994fa72322,PMC,here is an unquoted string,10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is a,",string,","within,", quotes.",2007-07-25
n9sih438,4994fa72322,PMC,"here is a,",string,","within,", quotes.",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is a,",string,","within,", quotes.",2007-07-25

, а затем написал этот скрипт (, используя GNU awk для 3-го аргумента для match()), чтобы определить, к какому типу входной строки относится каждая из них, а затем соответствующим образом изменить поле в кавычках (s ):

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    # The 4th and 9th fields may or may not be quoted so we are looking
    # for one of these patterns of fields:
    #
    #    1,2,3,4,5,6,7,8,9,10           - type A
    #    1,2,3,"4",5,6,7,8,9,10         - type B
    #    1,2,3,4,5,6,7,8,"9",10         - type C
    #    1,2,3,"4",5,6,7,8,"9",10       - type D
    #
    # If we can determine which type of record we have then we can
    # identify the fields.

    delete f
    if ( match($0,/^(([^",]+,){9}[^",]+)$/,a) ) {
        type = "A"
        split(a[0],f)
    }
    else if ( match($0,/^(([^",]+,){3})(".*"),(([^",]+,){5}[^",]+)$/,a) ) {
        type = "B"
        split(a[1],f)
        f[4] = a[3]
        split(a[4],tmp)
        for (i in tmp) {
            f[4+i] = tmp[i]
        }
    }
    else if ( match($0,/^(([^",]+,){8})(".*"),([^",]+)$/,a) ) {
        type = "C"
        split(a[1],f)
        f[9] = a[3]
        f[10] = a[4]
    }
    else if ( match($0,/^(([^",]+,){3})(".*"),(([^",]+,){4})(".*"),([^",]+)$/,a) ) {
        type = "D"
        split(a[1],f)
        f[4] = a[3]
        split(a[4],tmp)
        for (i in tmp) {
            f[4+i] = tmp[i]
        }
        f[9] = a[6]
        f[10] = a[7]
    }
    else {
        type = "Unknown"
        split($0,f)
        printf "Warning, could not classify file \"%s\", line %d: %s\n", FILENAME, FNR, $0 | "cat>&2"
    }

    # Uncomment the following lines to see what the above is doing:
    #print ORS "################" ORS "Type " type ":\t" $0
    #for (i=1; i in f; i++) {
        #print i, "<" f[i] ">"
    #}

    gsub(/^"|"$/,"",f[4])
    gsub(/"/,"\"\"",f[4])
    f[4] = "\"" f[4] "\""

    gsub(/^"|"$/,"",f[9])
    gsub(/"/,"\"\"",f[9])
    f[9] = "\"" f[9] "\""

    $0 = ""
    for (i in f) {
        $i = f[i]
    }
    print
}

.

$ awk -f tst.awk file
n9sih438,4994fa72322,PMC,"here is an unquoted string",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is an unquoted string",2007-07-25
n9sih438,4994fa72322,PMC,"here is a,"",string,"",""within,"", quotes.",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is an unquoted string",2007-07-25
n9sih438,4994fa72322,PMC,"here is an unquoted string",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is a,"",string,"",""within,"", quotes.",2007-07-25
n9sih438,4994fa72322,PMC,"here is a,"",string,"",""within,"", quotes.",10.1371/journal.pone.0000645,PMC1920550,17653272,cc-by,"here is a,"",string,"",""within,"", quotes.",2007-07-25

Вывод всегда заключает в кавычки 2 поля, которые могут быть заключены в кавычки во вводе. -Если вам это не нравится, это простая настройка, оставленная в качестве упражнения. Я также использовал более традиционный способ «экранирования» двойной кавычки в CSV, который заключается в ее удвоении. Опять тривиальное изменение, если вы предпочитаете \"вместо "". См.https://stackoverflow.com/questions/45420535/whats-the-most-robust-way-to-efficiently-parse-csv-using-awkдля получения дополнительной информации об использовании awk для CSV и "стандартов" CSV.

2
18.03.2021, 23:05

Теги

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