Questions answered

How to use variable in while loop?

The following scripts do not work properly:
  • VAR=0
    ls -1 | while read file
    do
        [ "$file" = "tmp" ] && VAR=1
    done
    echo $VAR # It turns out that $VAR is always zero here
  • echo "tmp.txt" | read file

If while loop consumes the input from the pipe, it is launched in a subshell, thus all changes to the variables inside the loop do not work as expected (are not propagated to calling shell). Solution: loop should be executed by primary shell:
  1. From Modifying variable inside while loop is not remembered:
    VAR=0
    while read file
    do
        [ "$file" = "tmp" ] && VAR=1
    done < <(ls -1)

    Process substitution which is used in above example, is described here. Another good application of process substitution is capturing the exit code of first command in a pipe:

    if mount /dev/sda /mnt 2> >(head -1)
    then
        ...
    fi

    The same way read and arrayread when applied after the pipe initialize the variable in a forked shell (hence echo file.txt | read line does not work) so the solution looks this:

    read file < <(echo file.txt)
  2. From Create variables and assign values via loop:
    VAR=0
    for file in $(ls -1)
    do
        [ "$file" = "tmp" ] && VAR=1
    done

How to evaluate the intersection of two lists?

Intersection of two lists:
  • cat 1.txt 2.txt | sort | uniq -d
  • comm -12 1.txt 2.txt

Symmetric difference of two lists:

  • cat 1.txt 2.txt | sort | uniq -u

How to redirect output to STDERR?

  • ( >&2 echo "bla-bla" );
  • echo "bla-bla" > /dev/stderr
  • ... | tee /dev/stderr | ...

How to initialize variable with here-document?

From How to assign a heredoc value to a variable in Bash:
read -r -d '' SCRIPT <<'EOS'
use strict;
 
my $lines = 0;
 
while (<>) {
    chomp;
 
    $files++;
}
 
print "Number of lines: $lines\n";
 
EOS
 
perl -e "$SCRIPT"

How to skip 1st line of output?

... | tail -n +2

How to read lines from file preserving leading spaces and without splitting?

From Use bash to read line by line and keep space and Bash read line does not read leading spaces:
while IFS= read -r line
do
    echo "$line"
done < some_file.txt

Similarly to read the whole file into variable:

IFS= FILE=`cat some_file`

How to list files with their sizes and MD5 sum?

(
echo -e "File\tMD5\tSize\tCTime"
find . -type f -printf '%p\t%s\t%T+\n' | sort -k1 -t$'\t' | while IFS= read -r line
do
     echo -e "$(md5sum "`echo "$line" | cut -f1`" | cut -f1 -d' ')\t$line"; \
done
) | column -t -s $'\t'

See also:

How to feed file names containing space to xargs?

How can I use xargs to copy files that have spaces and quotes in their names actually says that xargs should be tweaked, but if the list is produced by find then solutions are:
  • Use null separator: find ... -print0 | xargs -0 wc -l
  • Use find ability to append arguments: find ... -exec wc -l {} +

How to sum sequence of numbers?

seq 1 10 | paste -s -d+ | bc

How to count number of specific characters in the file?

$ cat file | tr -d -c '#' | wc -c

How to check if a string begins or ends with some value?

See Advanced Bash-Scripting Guide, Chapter 7:
if [[ $fullpath == *.txt ]]
then
    echo "This is text file"
fi

How to extract filename and extension?

From Extract filename and extension in bash:
file=`basename "$fullpath"`
extension=${file##*.}
filename=${file%.*}

How to append/prepend the string to each array element?

array=( "${array[@]/#/prefix_}" )
array=( "${array[@]/%/_suffix}" )

To print an array as new-line separated string:

IFS=$'\n' echo "${array[*]}"
IFS=$'\n' echo "$*" | xargs ...

How to generate random strings?

To generate e.g. 5 random passwords each having 16 characters in alphabet “A-Za-z0-9” use:
tr -dc A-Za-z0-9 < /dev/urandom | fold -w 16 | head -5

How to re-attach the process to another terminal?

$ myprog
# press Ctrl+Z to suspend the program
$ bg
$ disown
# switch to another terminal / screen / tmux session
$ reptyr $(pgrep myprog)

How to turn off bell?

To disable bash from sending bell to terminal add/uncomment the following in ~/.bashrc:
set bell-style none

However bell can be useful to notify long running task:

Turn off buffering for pipe

When data is output to stdout, one can see the result immediately (it flushes after each write). However if output is piped to another command, it is buffered, thus causing difficulties e.g. with tee utility.

The problem is solved using stdbuf utility:
stdbuf -oL tail -f /var/log/messages | tee logs.txt

Можно ли в UNIX обнулять (truncate) файл, в который пишет некоторый процесс?

Таким образом, оболочки sh и csh, а также tcsh при открытии нового файла, не используют флаг O_APPEND, а описанный выше способ обнуления используемых файлов в этих оболочках использовать не получится. В более современных оболочках (ksh, bash, zsh) этой проблемы нет.

software/bash.txt · Last modified: 2012/11/22 20:13 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki