简体   繁体   中英

Shell Script error: “head: invalid trailing option — 1”

I have this code in my shell(bash) script for splitting a file into smaller parts:

for (( i=$start; i<=$lineCount; i=i+$interval))
do
    temp=`expr $i + $interval`;
    if [ $temp -le $lineCount ]
    then
        command="head -$temp $fileName | tail -$interval > $tmpFileName";
        echo "Creating Temp File: $command";
    else
        lastLines=`expr $lineCount - $i`;
        command="head -$temp $fileName | tail -$lastLines > tmpFileName";
        echo "Creating Temp File: $command";
    fi
    `$command`;
done

It prints the following output on stdin:

Creating Temp File: head -10 tmp.txt | tail -10 > tmp.txt_TMP
head: invalid trailing option -- 1
Try `head --help' for more information.

But the command printed: head -10 tmp.txt | tail -10 > tmp.txt_TMP head -10 tmp.txt | tail -10 > tmp.txt_TMP runs correctly on the command line.

What am I doing wrong?

When you put the pipe | in a variable, the shell interprets it as an ordinary character and not as a pipe. Ditto for redirection operators like > , < , ...

An ugly way would be to use eval .

A better approach would be to split your command into different parts so as to get rid of pipes and redirection operators in it.

For example:

command="head -$temp $fileName | tail -$lastLines > tmpFileName";

would be written as:

cmd1="head -$temp $fileName";
cmd2="tail -$lastLines";

and executed by saying:

"$cmd1" | "$cmd2" > tmpFileName;

Moreover, you don't need backticks to execute a command that is stored in a variable. Simply say:

$command

Problem is here:

command="head -$temp $fileName | tail -$interval > $tmpFileName"

and later:

`$command`    

Instead of storing whole piped command in a string you can directly execute the command:

head -$temp "$fileName" | tail -$interval > "$tmpFileName"

There are several issues here. First of all, lets see our refactored version with correct quoting and many other improvements:

for (( i=start; i<=lineCount; i+=interval)); do
    ((temp = i + interval))
    if (( temp <= lineCount )); then
        echo "Creating Temp File using 'tail -n $interval'"
        head -n "$temp" "$fileName" | tail -n "$interval" > "$tmpFileName"
    else
        ((lastLines = lineCount - i))
        echo "Creating Temp File using 'tail -n $lastLines'"
        head -n "$temp" "$fileName" | tail -n "$lastLines" > "$tmpFileName"
    fi
done

I have changed all arithmetic expressions to correct syntax . This is what you want, because it is more readable.
Then, it seems like you want to put a command into a variable and then run it. To cut the story short, you simply should not do that. Here's why
Also, this is not c++, you don't have to place ; on every line.
You have also missed $ character in tmpFileName on the 10th line of your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM